1
votes

Scenario: I have a view controller (vc1) that presents another view controller (vc2). And then vc2 presents vc3. How can I set vc1 as a delegate for vc3?

Situation: While in vc3, I intend to pop back to vc1 and have it execute some code. But, since the vc3 instance is created in vc2, vc1 has no direct link to vc3 from vc1.

Here is a simplified picture of what I'm trying to achieve:

vc1

let vc2Instance = vc2()
navigationController?.pushViewController(vc2Instance)

class vc1: UIViewController, tellVC1ToDoSomethingDelegate {

    func vc1DoSomething(withThis: String) {
        // for instance: present another VC not currently in stack
        let randomVC = RandomVC()
    }
}

vc2

let vc3Instance = vc3()
navigationController?.pushViewController(vc3Instance)

vc3

protocol tellVc1ToDoSomethingDelegate() {
   func vc1DoSomething(withThis: String)
}

class vc3: UIViewController {
   weak var vc1Delegate: tellVC1ToDoSomethingDelegate?

   func pushRandomVCWithString(myString: String) {
      // code to dismiss view controllers up to vc1 in stack
      if let vcStack = self.navigationController?.viewControllers{
          self.navigationController?.popToViewController(vcStack[vcStack.count - 2], animated: true)

      vc1Delegate.vc1DoSomething(withThis: myString)
   }
}

Here's my issue: If I was marking vc1 as a delegate for vc2 (Just 1 VC up the stack), I'll simply type

let vc2Instance = vc2()
vc2Instance.vc1Delegate = self

How do I access self (of vc1) when no instance of vc3 exists in vc1? Is chaining delegates from vc3 to vc2 then to vc1 the only way out? I imagine this will be ugly when there are several vc's in-between.

2
You can just do delegate chaining, pass the delegate from vc1 -> vc2 -> vc3, then vc3 can call that delegate and dismiss both vc2 and vc3 - Tj3n

2 Answers

1
votes

There are two way to do this, one is delegation and another one is Notification.

  1. Delegation:

    As you asked, you are trying this one. Just:

    • create a delegate variable in vc2 and vc3 both.
    • while creating the object of vc2 in vc1 pass the self in the delegate variable of vc2.
    • while creating the object of vc3 in vc2 pass the self.delegate in the delegate variable of vc3.
    • Now as you call the method in vc3 like self.delegate?.anyMethod() will get the call in both vc2 and vc3.
  2. Notification:

    As of the notification you can broadcast a notification of custom type with some info for vc3. and can add observer to observe the notification in either in vc1 or any other vc, you will receive the call with passed data. Learn more about Notification here

As my personal suggestion first one is better in your case.

0
votes

In many ways you can achieve this. Some of them listed below.

  1. If VC1 is your root VC for the navigation stack you can use the below API in VC3

    popToRootViewController(animated:)

  2. Other way you can get the viewControllers array property from the navigationController and get the VC1 from the array and use the below API in VC3

    popToViewController(_:animated:)

Hope this help. Please comment any doubt.