UICollectionViewCell 中按钮的可用性?

Usability of a button inside a UICollectionViewCell?

我有一个 ProductVC.swift (ProductViewController) 文件和一个 ProductCell.swift。 ProductVC 包含一个 UICollectinView,ProductCell 是一个特定的 UICollectionViewCell。

ProductCell.xib 看起来像这样:

ProductVC 包含一个包含所有单元格数据(产品)的数组并填充单元格。

我的目标:用户应该有可能喜欢一个产品。他可以通过单击每个单元格右上角的“赞”按钮来完成。每个单元格显示一个由 productID 指定的特定产品。

我的问题:赞按钮操作(IBAction 函数)在 ProductCell 中。 ProductCell 没有单元格数据。单元格数据以数组形式存储在 ProductVC 中。所以我不知道如何捕捉用户想要喜欢的产品(productID)。

我的尝试: 使用下面的代码,我可以获得用户单击“赞”按钮的单元格的 indexPath。但我不能使用此 indexPath 获取产品数据,因为数据存储在 ProductVC 中。我也可以将数据存储在 ProductCell 中,但这不是一种干净的方式。 mb 是否可以将此 indexPath 提供给 ProductVC?

extension UICollectionView {
    func indexPathForView(_ view: UIView) -> IndexPath? {
        let center = view.center
        let viewCenter = self.convert(center, from: view.superview)
        let indexPath = self.indexPathForItem(at: viewCenter)
        return indexPath
    } 
}

let superview = self.superview as! UICollectionView
    
if let indexPath = superview.indexPathForView(button) {
    print(indexPath) // indexPath of the cell where the button was pressed
}

已解决 解决方法是回调闭包:

//UICollectionViewCell
var saveProductLike: ((_ index: Int) -> Void)?
@IBAction func likedButtonClicked(_ sender: UIButton) {
    print("Liked button clicked!")
    let productArrayIndex = calculateProductArrayIndex(for: sender)
    saveProductLike?(productArrayIndex!)
}

//UIViewController
cell.saveProductLike = { (index) -> Void in
    print(index)  
}

有多种方法可以解决这个问题,但我将讨论最常见的一种方法,即使用委托。

protocol ProductCellDelegate: AnyObject {
  func productCellDidPressLikeButton(_ cell: ProductCell)
} 

ProductCell中定义一个属性weak var delegate: ProductCellDelegate?并在like按钮的目标动作中通知你的代理人

@objc private likeButtonPressed(_ sender: Any) {
  delegate?.productCellDidPressLikeButton(self)
}

在您的视图控制器中,您可以遵循协议并像这样实现它:

func productCellDidPressLikeButton(_ cell: ProductCell) {
  guard let ip = collectionView.indexPath(for: cell) else { return }
  // process event, get product via index...
}

然后你需要将视图控制器设置为 collectionView(_:willDisplay:forItemAt:) 中的委托或 collectionView(_:cellForItemAt:): cell.delegate = self.