2
votes

I have an extension of UICollectionViewCell class. When something is pressed in this cell, I am trying to notify the Controller. I am not quite sure if the protocol delegate pattern is the way to go about it. I am not sure how to use it in this case. I have the following class outside my extension of UICollectionViewCell class.

protocol bundleThreadsDelegate: class { func bundleThreadsDidSelect(_ viewController: UIViewController) }

And I have the following property:

public weak var delegate: bundleThreadsDelegate? in my extension.

I am not quite sure where to go on from Here. Please help.

3

3 Answers

1
votes

You said "when something is pressed in this cell", not when the cell itself is pressed, so I assume you may want multiple actionable items in your cell. If that's what you really mean then in your UICollectionViewCell, you could simply add a UIButton (no need for delegates as mentioned here because everything can happen within the same view controller—use delegates when communicating between different objects):

class MyCollectionViewCell: UICollectionViewCell {

    let someButton = UIButton()

    ...

}

When you create the UICollectionView, to make it easiest, set the view controller it's in as the data source:

let myCollection = UICollectionView(frame: .zero, collectionViewLayout: MyCollectionViewFlowLayout())
myCollection.dataSource = self
...

Then in your data source, which would be in something like MyViewController, give the button a target:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let path = indexPath.item
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! MyCollectionViewCell
    cell.someButton.addTarget(self, action: #selector(someButtonAction(_:)), for: .touchUpInside)
    return cell

}

And make sure that the action method is also in MyViewController along with the data source.

@objc func someButtonAction(_ sender: UIButton) {

    print("My collection view cell was tapped")

}

Now you can have multiple buttons within one collection view cell that do different things. You can also pass in arguments from the cell to the button action for further customization.

However, if you want action when the entire cell is pressed, use the delegate method already mentioned (or make the entire cell a UIButton which is not as elegant but that's open to interpretation).

0
votes

Use this CollectionView Delegate method to notify the ViewController when your cell is selected by a user.

     func collectionView(_ collectionView: UICollectionView, 
                     didSelectItemAt indexPath: IndexPath)
0
votes

Chris is correct, assuming you're only interested in the whole cell being selected. If you have a button or something within your cell and it's that press event you're interested in then yeah, you could use a delegate.

As an aside, protocols usually start with an uppercase letter, i.e. BundleThreadsDelegate rather than bundleThreadsDelegate, but that's up to you. Your general approach could be something like this (note this is pseudo code):

   protocol YourProtocol {
     func didPressYourButton()
   } 

   class YourCell {
      @IBOutlet weak var yourButton: UIButton!
      public weak var yourButtonDelegate: YourProtocol?

      func awakeFromNib() {
        super.awakeFromNib()
        yourButton.addTarget(self, action: #selector(didPressYourButton), for: .touchUpInside)
      }

    func didPressYourButton() {
      yourButtonDelegate?.didPressYourButton()
    }
  }

And then in your view controller's cellForRowAt function:

let cell = ...
cell.yourButtonDelegate = self

Then conform to the protocol and implement the method in your view controller:

extension YourViewController: YourProtocol {

  func didPressYourButton() {
    doAllTheThings()
  }

}