我正在学习combine我想用combine代替cell和tableview之间的委托。我已经设法连接和接收信息,但问题是当单元被重用时,每次我生成相同的事件时,我接收它的次数与以前在该重用单元中使用的次数一样多。
我在视图控制器中声明了可取消对象
var cancellables: Set<AnyCancellable> = []
这是cellForRow方法
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.celdaReuseIdentifier, for: indexPath)
as? MyCell else {
return MyCell()
}
cell.index = indexPath
cell.lbTitle.text = String("Cell (indexPath.row)")
cell.tapButton.compactMap{$0}
.sink { index in
print("tap button in cell (index.row)")
}.store(in: &cancellables)
return cell
}
,单元格是
class MyCell: UITableViewCell {
static let cellNibName = "MyCell"
static let celdaReuseIdentifier = "MyCellReuseIdentifier"
@IBOutlet weak var lbTitle: UILabel!
@IBOutlet weak var button: UIButton!
var index: IndexPath?
let tapButton = PassthroughSubject<IndexPath?, Never>()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
@IBAction func tapButton(_ sender: Any) {
self.tapButton.send(index)
}
}
谢谢你的帮助
要解决重复使用单元格的问题,您必须添加Set
如果你只打算在单元格中使用一个事件,你可以使用一个AnyCancellable:
单事件(AnyCancellable)
声明AnyCancellable类型单元格中的变量。每次单元格被重用时,都会添加一个新的发布者来替换以前的发布者,并且您不会多次收到该事件。
细胞class MyCell: UITableViewCell { static let cellNibName = "MyCell" static let celdaReuseIdentifier = "MyCellReuseIdentifier" @IBOutlet weak var lbTitle: UILabel! @IBOutlet weak var button: UIButton! var index: IndexPath? // store publisher here var cancellable: AnyCancellable? // Single Publisher per cell let tapButton = PassthroughSubject<IndexPath?, Never>() override func awakeFromNib() { super.awakeFromNib() } @IBAction func tapButton(_ sender: Any) { self.tapButton.send(index) } }
ViewController
在Viewcontroller中,你只需要将publisher添加到cancellable。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.celdaReuseIdentifier, for: indexPath)
as? MyCell else {
return MyCell()
}
cell.index = indexPath
cell.lbTitle.text = String("Cell (indexPath.row)")
// Add your publisher to your cancellable and remove store function.
cell.cancellable = cell.tapButton.compactMap{$0} .sink { index in
print("tap button in cell (index.row)")
}
return cell
}
多个事件(Set )
这里是相同的,但如果你想要有更多的事件,使用集合。
细胞创建变量Set
class MyCell: UITableViewCell {
static let cellNibName = "MyCell"
static let celdaReuseIdentifier = "MyCellReuseIdentifier"
@IBOutlet weak var lbTitle: UILabel!
@IBOutlet weak var button: UIButton!
var cancellables: Set<AnyCancellable>?
var index: IndexPath?
// Multiple Publishers per cell
let tapButton = PassthroughSubject<IndexPath?, Never>()
let tapView = PassthroughSubject<UIImage, Never>()
// Remove all suscriptions before reuse cell
override func prepareForReuse() {
super.prepareForReuse()
cancellables.removeAll()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
@IBAction func tapButton(_ sender: Any) {
self.tapButton.send(index)
}
}
ViewController
在Viewcontroller中你只需要存储publisher。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.celdaReuseIdentifier, for: indexPath)
as? MyCell else {
return MyCell()
}
cell.index = indexPath
cell.lbTitle.text = String("Cell (indexPath.row)")
// Add your publisher to your cell´s collection of AnyCancellable
cell.tapButton.compactMap{$0}
.sink { index in
print("tap button in cell (index.row)")
}.store(in: &cell.cancellables)
return cell
}
祝你好运! !😉
你已经完美地分析和描述了这个问题。所以原因很清楚。查看您的cellForRow
实现并思考它的作用:您正在创建并添加新的管道到你的cancellables
每次你的cellForRow
运行时,不管你是否已经已经为这个单元格的实例化添加了管道。
所以你需要一种不这样做的方法。你能想到一个办法吗?提示:将管道连接到单元格并从那里输出,因此每个单元格只有一个。你的Set不会两次添加相同的管道,因为它是一个Set。