5

Sorry in advance that I can’t explain myself very well. I’m really new to programming and the topic of delegation still eludes me. I had some great help with this once before, but now I am trying to use a delegate in a different situation and I can’t get it right. I pieced together a bit of code that doesn’t work, and no matter how much I search I can’t find a way to fix it.

I have a view controller (MainController) with and embedded view controller (EmbeddedController) in a container view. I am trying to have a button in the embedded controller manipulate the container view (containerView).

EmbeddedController:

protocol ControllerDelegate {
    func hideContainerView()
}

class EmbeddedController: UIViewController {
    var delegate: VControllerDelegate?

    @IBAction func button(sender: AnyObject) {
    delegate?.hideContainerView()
    }
}

MainController:

class MainController: UIViewController, ControllerDelegate {

    @IBOutlet var containerView: UIView!

    func hideContainerView() {
    containerView.hidden = true
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        var vc = EmbeddedController()
        vc.delegate = self
    }
}

Does anyone have any idea what I am doing wrong? And why this isn’t working?

Community
  • 1
  • 1
HugoLXO
  • 222
  • 3
  • 10

2 Answers2

9

What I ended up doing is adding this to the MainController:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if (segue.identifier == "mySegue") {
        let vc = segue.destinationViewController as! EmbeddedController
        vc.delegate = self
    }
}

In storyboard I selected the segue from the MainController to the EmbeddedController, and set the identifier to "mySegue".

Without the code above the delegate kept returning nil. I didn't look into this solution at first as I thought segues were only for transitioning between view controllers, and in my mind I didn't see the embedded controller as a transition. Maybe someone more knowledgable than me (which is practically anyone on here at this point) can explain how this is all fitting together.

In any case, this is how I solved my issue and hopefully someone else can benefit from this as well :)

HugoLXO
  • 222
  • 3
  • 10
2

First of all, to avoid strong reference cycles:

protocol ControllerDelegate: class {
    func hideContainerView()
}

class EmbeddedController: UIViewController {
    weak var delegate: ControllerDelegate?

And you haven't added your newly instantiated VC view to container view, and not added it as a child VC:

        let vc = EmbeddedController()
        vc.delegate = self
        containerView.addSubview(vc.view)
        self.addChildViewController(vc)
        vc.didMoveToParentViewController(self)
rshev
  • 4,086
  • 1
  • 23
  • 32
  • I have to research these strong references, I may have been doing it wrong everywhere. It is hard to learn some of these things only from books without a tutor of some kind... I didn't add it as a child VC because I thought this went automatically as I created everything through the storyboard. I will go try your solution now, thanks! – HugoLXO Aug 12 '15 at 21:58
  • Sadly this doesn't work, the button becomes un-tappable. If I remove `containerView.addSubview(vc.view)` the button is tappable again, but the view still doesn't get hidden. Thank you for your good intent though! – HugoLXO Aug 12 '15 at 22:37
  • Is button 100% on the embedded view, not on the container view? – rshev Aug 13 '15 at 05:36
  • Yes, everything was made with storyboard and the button is in the embedded controller. So in my storyboard I have 2 view controllers, the main controller with a container view, connected to the embedded controller that has the button in it. mainController -> embeddedController -> button – HugoLXO Aug 13 '15 at 09:15
  • If the embedded controller is connected to container via storyboard embed segue, you don't need any code in main's viewDidLoad. You can connect delegate to MainVC in storyboard (last tab in right properties pane). – rshev Aug 13 '15 at 09:40
  • If i try to connect them the "delegate"doesn't appear on the list, only segues. Sorry rshev, feeling pretty stupid right now, I just can't figure it out... – HugoLXO Aug 13 '15 at 10:14
  • Thank you so much for trying to help! I added an answer on how I managed to solve it. Can't say I understand it well, but it works :) – HugoLXO Aug 13 '15 at 13:00
  • Using 'class' keyword to define a class-constrained protocol is deprecated, we need to use 'AnyObject' instead. protocol ControllerDelegate: AnyObject { func hideContainerView() } – Dayanithi Natarajan Nov 21 '21 at 18:54