UICollectionViewCell 与它的 UICollectionViewController 对话

UICollectionViewCell Talking to Its UICollectionViewController

虽然可能是主观的,但我想知道如何去拥有一个自定义 UICollectionViewCell,当它的 UIButton 被按下时,通知自定义 UICollectionViewController 要做什么。

我的第一个想法是在 CustomCell 中使用 delegate,如下所示:

class CustomCell: UICollectionViewCell {

    var delegate: CustomCellDelegate?

    static let reuseIdentifier = "CustomCell"

    @IBOutlet weak private var button: UIButton! {
        didSet {
            button.addTarget(self, action: #selector(self.toggleButton), for: .touchUpInside)
        }
    }

    @objc private func toggleButton() {
        delegate?.didToggleButton()
    }

}

其中 CustomCellDelegate 的 class 协议定义为:

protocol CustomCellDelegate: class {
    func didToggleButton()
}

然后UICollectionViewController实现了didToggleButton函数并将自己作为delegate分配给每个单元格如下:

class CustomCollectionViewController: UICollectionViewController, CustomCellDelegate {

    func didToggleButton() {
        // do some stuff and then update the cells accordingly ...
        collectionView?.reloadData()
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let customCell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCell.reuseIdentifier, for: indexPath) as? CustomCell else { fatalError("Unexpected indexPath") }
        customCell.delegate = self
        return customCell
    }
}

这是解决此问题的正确方法吗,还是有另一种方法可以在 UICollectionViewCell 与其父控制器之间进行通信?

感谢您的任何建议。

是的,当通信必须只与一个 object 进行时,委托是最佳选择。在这种情况下 parent UICollectionViewController

其他通信方式是-

通知:当我们想要传达多个 objects post 通知时。

KVO:了解 value/property 何时更改。但请谨慎使用。

是的,这确实是正确的解决方案。您的自定义单元是盲目的,它们对您的控制器一无所知。他们只触发委托方法。

但是,还有一个更正确的解决方案,那就是观察。有人喜欢授权,有人喜欢观察。您可以使用 NotificationCenter 到 post 关于单元格中发生的触摸的通知,并使您的控制器成为对这些通知做出反应的观察者。

// inside your cell
NotificationCenter.default.post(name: Notification.Name("ButtonPressed"), object: nil)

// inside your controller
NotificationCenter.default.addObserver(self, selector: #selector(someHandler), name: Notification.Name("ButtonPressed"), object: nil)

你的 func someHandler() 将在你的控制器(观察者)捕获到 posted 事件时处理调用。

此外,还有 KVO,但它很乱而且不适合那种特殊情况,因为你有多个单元格。

设置通信通道的另一种方法是绑定。它既可以是手动编写的,也可以是反应式的(例如,使用 ReactiveSwift)。

例如手动一:

// in your controller 
cell.pressHandler = {
    // do something
    ...
}

// in your cell
var pressHandler: (() -> Void)?

...

// when the button is pressed you execute that handler
pressHandler?()