9

How can I add a view of a child view controller to a custom UITableViewCell? I can add the view like this inside cellForRowAtIndexPath:

self.addChildViewController(controlsViewController)
cell!.cellView.addSubview(controlsViewController.view)
controlsViewController.didMoveToParentViewController(self)

But when the cell disappears, I need to remove this child view controller. I'm not really sure how to do that. Is there a better way to go about this?

Tometoyou
  • 7,792
  • 12
  • 62
  • 108
  • "How can I add a view of a child view controller to a custom UITableViewCell?" Don't. This is not a good use of a child view controller. Just add a view and forget about view controllers in this situation. – matt Jun 12 '15 at 22:16
  • That seems to make sense. I've been trying to convert everything to use MVC but this part is being a nightmare! If you post your comment as an answer I'll mark it correct! – Tometoyou Jun 12 '15 at 22:19

2 Answers2

9

Do it via delegation. I have done on collection view ,you can do it on tableview too. follow the below steps

1 .In your custom cell class create a delegateHandler and override your awakeFromNib() method. eg

protocol BibleReadingSliderProtocol: class {
    func addThisViewControllerAsChild(audioViewController :AudioViewController)
}

class BibleReadingSliderCollectionCell: UICollectionViewCell {

    @IBOutlet weak var containerView: UIView!

    var audioVC = AudioViewController()
    weak var bibleReadingSliderDelegate:BibleReadingSliderProtocol?

    override func awakeFromNib() {
        super.awakeFromNib()

        print("Awake call from cell")
        // Initialization code

         let storyboard = UIStoryboard(name: "Main", bundle: nil)
        audioVC  = storyboard.instantiateViewController(withIdentifier: "AudioViewController") as! AudioViewController
        audioVC.view.frame = self.containerView.bounds
        self.containerView.addSubview(audioVC.view)

        if self.bibleReadingSliderDelegate != nil {
            self.bibleReadingSliderDelegate?.addThisViewControllerAsChild(audioViewController: audioVC)
        }

    }
}
  1. In your ViewController where you are using this custome cell (either tableview or collection view) define the delegate hander

    func addThisViewControllerAsChild(audioViewController: AudioViewController) {
        self.addChildViewController(audioViewController);
     }
    

And Dont forget to set your delegate to this viewcontroller in cellForItemAt/cellForRowAt

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

    let imageSliderCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! BibleReadingSliderCollectionCell

    imageSliderCollectionViewCell.bibleReadingSliderDelegate = self
    return imageSliderCollectionViewCell
}
Sonius
  • 1,597
  • 3
  • 14
  • 33
Chandramani
  • 871
  • 1
  • 12
  • 11
3

Don't misunderstand MVC. Not every view in the world needs to have its own personal view controller! A main view has a view controller, but a button in that main view does not have its own personal view controller; it simply talks to the main view's view controller.

The same is true of this view. Views can come and go very easily; do not add the heavyweight burden of an additional view controller when you don't need to! Just grab the view (somehow) and stick it into the cell's contentView or remove it from the cell's contentView in cellForRowAtIndexPath:, just like any other view - but manage it using your table view controller or table view data source / delegate or whatever is in charge here. Don't add an extra view controller to the story just for the sake of this one little view. That's likely to be a bad use of view controllers.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 2
    The only reason I was trying to make this have a view controller was because there's some extra logic associated with it where that overlaid view should communicate to a server when a button in that view is pressed. I guess I can communicate to the server class from the view but it seems a bit wrong. – Tometoyou Jun 12 '15 at 22:29
  • I understand perfectly and I guessed that this might be the case, but there are other patterns for encapsulating that special logic than using an extra view controller. – matt Jun 12 '15 at 22:29
  • What patterns do you recommend? At the moment the code that communicates with the server is a singleton and I call a function in the singleton from a button press in the view. – Tometoyou Jun 12 '15 at 22:31
  • Well, if the only place where this view ever appears is in this one table view, then it can perfectly well be managed by the same view controller that manages the table view. If that feels horrible, then the table's view controller might have some sort of helper object to which you point this view's management when you insert it into the interface. – matt Jun 12 '15 at 22:32
  • The proper pattern is to use a delegate to callback to the view controller which then communicates with the server and updates the cell appropriately. – DBoyer Jun 12 '15 at 23:40
  • @DBoyer, you can't say that's the "proper pattern". You could easily add an extension to UIView to traverse the Response chain in order to find the first responder VC in the hierarchy. You could also set a weak variable to hold a reference, use segues with static cells. There are quite a few ways to approach this. Some apps have insane complexity and require dynamism that invalidates there being one 'right' way. – TheCodingArt Jan 10 '17 at 14:13
  • I was referring this https://khanlou.com/2015/04/view-controllers-in-cells/ to implement some sort of appstore ui with multiple types collection views under tableview. Until now it was fine but cell doesn't resize properly in case of self sizing if you are using some container cell and keep changing the controller's view with different height on reused cell – Amber K Oct 24 '21 at 19:35