0

I have a function within a UICollectionViewCell that requires access to the hosting UIViewController. Currently 'makeContribution()' can't be accessed:

enter image description here

What is the proper way of accessing the host UIViewController that has the desired function?

Frederick C. Lee
  • 9,019
  • 17
  • 64
  • 105

3 Answers3

3

Thanks to the insightful responses, here's the solution via delegation:

enter image description here

...

enter image description here

...

enter image description here

...

enter image description here

{makeContribution}
Frederick C. Lee
  • 9,019
  • 17
  • 64
  • 105
1

This is a mildly controversial question - the answer depends a little on your philosophy about MVC. Three (of possibly many) options would be:

  1. Move the @IBAction to the view controller. Problem solved, but it might not be possible in your case.

  2. Create a delegate. This would allow the coupling to be loose - you could create a ContributionDelegate protocol with the makeContribution() method, make your view controller conform to it, and then assign the view controller as a weak var contributionDelegate: ContributionDelegate? in your cell class. Then you just call:

    contributionDelegate?.makeContribution()
    
  3. Run up the NSResponder chain. This answer has a Swift extension on UIView that finds the first parent view controller, so you could use that:

    extension UIView {
        func parentViewController() -> UIViewController? {
            var parentResponder: UIResponder? = self
            while true {
                if parentResponder == nil {
                    return nil
                }
                parentResponder = parentResponder!.nextResponder()
                if parentResponder is UIViewController {
                    return (parentResponder as UIViewController)
                }
            }
        }
    }
    
    // in your code:
    if let parentVC = parentViewController() as? MyViewController {
        parentVC.makeContribution()
    }
    
Community
  • 1
  • 1
Nate Cook
  • 92,417
  • 32
  • 217
  • 178
0

Well, CollectionView or TableView?

Anyway, Set your ViewController as a delegate of the cell. like this:

@objc protocol ContributeCellDelegate {
     func contributeCellWantsMakeContribution(cell:ContributeCell)
}

class ContributeCell: UICollectionViewCell {

    // ...

    weak var delegate:ContributeCellDelegate?

    @IBAction func contributeAction(sender:UISegmentedControl) {
        let isContribute = (sender.selectedSegmentIndex == 1)

        if isContribute {
            self.delegate?.contributeCellWantsMakeContribution(self)
        }
        else {
        }
    }
}


class ViewController: UIViewController, UICollectionViewDataSource, ContributeCellDelegate {

    // ...

    func collectionView(_ collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        cell = ...

        if cell = cell as? ContributeTableViewCell {
            cell.delegate = self
        }

        return cell
    }

    // MARK: ContributeCellDelegate methods

    func contributeCellWantsMakeContribution(cell:ContributeCell) {
        // do your work.
    }
}
rintaro
  • 51,423
  • 14
  • 131
  • 139