PublishSubject既是一個(gè)觀察者,也是一個(gè)被觀察者,通常用來(lái)代替delegate。如下需求:
思路很簡(jiǎn)單,點(diǎn)擊cell里刪除按鈕,用PublishSubject將刪除事件回調(diào)給ViewController,在ViewController里刪除數(shù)據(jù)源,再更新tableView。
在cell里定義屬性,row用定位數(shù)據(jù)源位置,這里情況特殊,數(shù)據(jù)源的index和cell的row一一對(duì)應(yīng),傳入row,相當(dāng)于數(shù)據(jù)源的index,到時(shí)候回調(diào)出去,就知道刪除哪條數(shù)據(jù):
var row: Int?
var deletePulish = PublishSubject<Int>()
點(diǎn)擊刪除,將傳入的row回調(diào)出去:
btnDelete.rx.tap.subscribe(onNext: { [weak self] in
if let row = self?.row {
self?.deletePulish.onNext(row)
}
}).disposed(by: disposeBag)
在ViewController里:
usersRelay.bind(to: tbl.rx.items(cellIdentifier: "SelectedMemberCell", cellType: SelectedMemberCell.self)) { (row, element, cell) in
cell.lblName.text = element.userName
cell.row = row
cell.deletePulish.subscribe(onNext: { [weak self] row in
self?.users.remove(at: row)
if let users = self?.users {
self?.usersRelay.accept(users)
}
}).disposed(by: self.disposeBag)
}
.disposed(by: disposeBag)
以上都是很正常的用法。
這里隱藏了一個(gè)問題。
我點(diǎn)擊刪除孟浩然,正常。
我再點(diǎn)擊刪除杜甫,卻刪除了杜甫和李白兩條。
經(jīng)過(guò)調(diào)試,發(fā)現(xiàn),cell的點(diǎn)擊刪除事件的確只發(fā)觸發(fā)一次,onNext發(fā)送刪除事件也只有一次。
但是ViewController里訂閱事件的確執(zhí)行了兩次。那么問題就在于為什么發(fā)送一次,會(huì)接收兩次?
只有一種可能,就是有兩個(gè)對(duì)象訂閱了同一個(gè)事件。
經(jīng)過(guò)增加更多的數(shù)據(jù)發(fā)現(xiàn)規(guī)律,點(diǎn)一次刪除一條,再點(diǎn)一次刪除兩條,第三次刪除三條。。。。。。很顯然,之前被刪除的cell依然再接收事件。所以,問題在于,之前的cell雖然從數(shù)據(jù)源上刪除了,導(dǎo)致不顯示,但是cell本身并沒有dealloc,也就是還在內(nèi)存里,依然會(huì)接收事件。
在ViewController里加上一句cell.deletePulish = PublishSubject<Int>(),將刪除的cell里的訂閱者重新賦值,就不會(huì)再接收到事件,如果deletePulish定義為可選類型,那么可以直接設(shè)為cell.deletePulish = nil。
usersRelay.bind(to: tbl.rx.items(cellIdentifier: "SelectedMemberCell", cellType: SelectedMemberCell.self)) { (row, element, cell) in
cell.lblName.text = element.userName
cell.row = row
cell.deletePulish.subscribe(onNext: { [weak self] row in
cell.deletePulish = PublishSubject<Int>()
self?.users.remove(at: row)
if let users = self?.users {
self?.usersRelay.accept(users)
}
}).disposed(by: self.disposeBag)
}
.disposed(by: disposeBag)