使用 Combine repeat values 连接 UITableviewCell 和 UITableview

Connect UITableviewCell with UITableview using Combine repeat values

我正在学习 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{[=11=]}
        .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)
}
}

感谢您的帮助

您把问题分析描述的很到位。所以原因很清楚。查看您的 cellForRow 实施并思考它的作用:您正在 创建并添加一个 管道 到您的 cancellables 次你的cellForRow运行,无论你是否已经为这个单元实例化添加了一个管道。

所以你需要一种不这样做的方法。你能想办法吗?提示:将管道连接到 cell 并从那里出售,因此每个 cell 只有一个 。您的 Set 不会两次添加 相同的 管道,因为它是一个 Set。

要解决重复使用单元格的问题,您必须将 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 中,您只需将发布者添加到可取消项中。

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{[=11=]} .sink { index in
        print("tap button in cell \(index.row)")
    }

    return cell
}

多个事件(设置

这里是一样的,但是使用集合以防你想要更多的事件。

  • 单元格

创建一个变量 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 中,您只需存储发布者。

  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{[=13=]}
        .sink { index in
        print("tap button in cell \(index.row)")
    }.store(in: &cell.cancellables)
    
      return cell
 }

祝你好运!!