如何通过协议和委托从 UITableViewCell 中的 UICollectionViewCell 传递数据以执行 segue 发件人?

how to pass data in perform segue sender through protocol & delegate from a UICollectionViewCell inside UITableViewCell?

  1. 我有 VC(a) 和 TableView
  2. 在UITableViewCell.xib里面我安装了一个UICollectionView
  3. UICollectionViewCell里面注册的UITableViewCell.xib 当然。
  4. 我想在 UICollectionViewCell didSelected
  5. 时执行从 VC(a) 到 VC(b) 的转场
  6. 而且由于 UICollectionViewCell 是在 UITableViewCell.xib 所以我不能使用 performSegue(withIdentifier: String, sender: Any) 在 .xib 文件中,因为它不是 继承自 UIViewController

我在 Whosebug 中进行了一些搜索,我找到了通过创建自定义委托协议来执行 segue 的方法我应用了该协议,除了发件人之外一切似乎都正常!!

我知道如何在没有协议的情况下在VC中使用它,但我不知道在应用协议后如何使用它

我是 Swift 语言的新手,所以请帮助我完成我的代码

下面是UITableViewCell.xib代码

protocol MyCustomCellDelegator {
    func cellWasPressed()
}


class AdminPList_TableViewCell: UITableViewCell {
    
    var delegate: MyCustomCellDelegator?
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        setupCell()
        getFProducts()
    }
    
    @IBOutlet weak var CollectionView: UICollectionView!
    
    func getFProducts() {
        productAPI.GetAllproducts { (appendThisProduct) in
            self.FP_Array.append(appendThisProduct)
            self.CollectionView.reloadData()
        }
    }
    
    var FP_Array : [productObject] = []    
}

extension AdminPList_TableViewCell : UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    func setupCell() {
        CollectionView.delegate = self ; CollectionView.dataSource = self

        CollectionView.register(UINib(nibName: "FproductsCell", bundle: nil), forCellWithReuseIdentifier: "FPcell")

//      CollectionView.register(UINib(nibName: "TproductsCell", bundle: nil), forCellWithReuseIdentifier: "TPcell")
        
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        return CGSize(width: self.CollectionView.frame.size.width-10, height: self.CollectionView.frame.size.height)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {  // make spacing between each cell
        return 10
    }

    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        return FP_Array.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let FPcell = CollectionView.dequeueReusableCell(withReuseIdentifier: "FPcell", for: indexPath) as! FproductsCell
        
        FPcell.UpdateFP_cell_Content(RetrivedProducts: FP_Array[indexPath.row])
        
        return FPcell
    }
    
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        let selectedProduct = FP_Array[indexPath.row] // I want to pass it to sender in perform segue un ProductsLibrary Class

//      print (selectedProduct.productName)
        self.delegate?.cellWasPressed()
        
    }
}

帮我把 selectedProduct 传到下面的协议中执行 segue

下面是安装 UITableView 的VC(a):

class ProductsLibrary : UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupCell()
    }
    
    @IBOutlet weak var TableView: UITableView!

    
}



extension ProductsLibrary : UITableViewDelegate, UITableViewDataSource, MyCustomCellDelegator {
    
    func cellWasPressed(withData:  productObject) {
        performSegue(withIdentifier: "EditProduct", sender: self)
        
    }
    
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let next = segue.destination as? ProductManagement{
            print ("Editing Product is Active")

              let product = sender as? productObject
                print(product) //it shows nil !!!
                next.EditingProduct = product
        }
    }
    
    func setupCell() {
        TableView.delegate = self ; TableView.dataSource = self
        
        TableView.register(UINib(nibName: "AdminPList_TableViewCell", bundle: nil), forCellReuseIdentifier: "PLcell")
    }
    
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                    
        return 3
    }
    
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                        
        let cell = tableView.dequeueReusableCell(withIdentifier: "PLcell", for: indexPath) as! AdminPList_TableViewCell
            
        cell.delegate = self
        
        
            return cell
    }
    
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        
        return self.TableView.frame.size.height/3
    }
    

    
    
}

你好吗?

也许你的 delegate 是 nil,这就是你 func callWasPressed() 没有调用的原因。

实例化单元后,您需要在 VC 上设置委托。

像这样:

AdminPList_TableViewCell.delegate = self

希望对你有所帮助!

编码愉快=D

当我开始学习 delegation 模式时,我总是犯一些错误。所以我给自己定了一个规则。当您必须实施委托时,请始终提醒 6 个步骤

前 3 步是 class 将传递数据或写入协议 ,这里是你的 AdminPList_TableViewCell 就是 class。 3 个步骤是

  1. 写一个协议(一堆方法声明)//你做到了。
  2. 在 class 中声明一个将传递数据的协议变量。 // 你也这样做了 (var delegate: MyCustomCellDelegator?)
  3. 调用您声明的方法。 // 你做到了 (self.delegate?.cellWasPressed())

最后 3 个步骤是针对 class 的,它将符合该协议 ,这里 ProductsLibrary 是 class.

  1. 在将实现这些方法的 class 中遵守该协议。 // 这里你做了 (extension ProductsLibrary: ..., MyCustomCellDelegator)

  2. 将delegate赋值给self,但是这里的self是什么?好吧,self 就是被委托的 ProductsLibrary! // 你错过了

  3. 实现协议方法。 // 你做到了 :)

如何解决?

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                    
    ...
    cell.delegate = self // you missed this line
    ...
    return cell
}

现在通过 selectedProduct 只需更改各处的协议方法定义即可。

protocol MyCustomCellDelegator {
    func cellWasPressed(withData: productObject)
}

然后从didSelectItemAt方法调用

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    let selectedProduct = FP_Array[indexPath.row] // I want to pass it to sender in perform segue un ProductsLibrary Class
    self.delegate?.cellWasPressed(withData: selectedProduct)
        
}

现在在方法体内使用它。

func cellWasPressed(withData data: productObject) {
    //now use the data and write your necessary code.
    performSegue(withIdentifier: "EditProduct", sender: self)

}

希望对您有所帮助:).

要通过其他对象传递对象 VC 您需要执行以下 3 个步骤:

1st: 在你的新 VC 上创建一个 var:

var selectedObject: YourKindObject?

第二步:像这样将您的对象传递给发件人:

func cellWasPressed(withData data: productObject) {
// pass productObject as sender
performSegue(withIdentifier: "EditProduct", sender: productObject)}

3rd:在你的覆盖方法中,你应该捕获你的 segue ID 和 passthroug 对象,像这样:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "YourID(Can be setted on storyboard segue identifier))" {
            var object = sender as! YourKindObject
            let controller = segue.destination as? VC
            controller?. selectedObject = object
    }
}