1

I have two UIViewControllers, vc1, and vc2. vc1 is embedded in a UIViewController which is embedded in a UITabBarController, but vc2 is not embedded in either.

How do I pass information from vc2 to vc1? After a user performs an action the data is saved and vc2 simply closes, so there isn't a segue to pass information. Obviously I can't reference vc1 through the Navigation stack or the TabController.

I could save to the AppDelegate, but I've read this isn't a good practice.

This is the code I use to pass information from AppDelegate to vc1 I tried it in vc2, but obviously it failed.:

let tabBarController = window!.rootViewController as! UITabBarController
        if let tabBarViewControllers = tabBarController.viewControllers {
           let navPostViewController = tabBarViewControllers[0] as! UINavigationController

                let user = User(context: managedObjectContext)

                if user.userID  != nil {
                    print("User is loggedIn")
                    isUserLoggedIn = true
                } else {
                    print("User is not loggedIn")
                    isUserLoggedIn = false
                }
                let postViewController = navPostViewController.topViewController as! PostViewController
                postViewController.managedObjectContext = managedObjectContext
        }
brimstone
  • 3,370
  • 3
  • 28
  • 49
Martin Muldoon
  • 3,388
  • 4
  • 24
  • 55
  • There's nothing intrinsically wrong with using the AppDelegate to hold key data like this. You could also use a singleton to hold your data model. Some people would advocate writing to the UserDefaults to hold the data - but that seems the wrong approach for dynamic data such as login status. Some people will certainly object to these approaches - but you have to find what works best for your scenario – Russell May 23 '17 at 16:53
  • 2
    Did VC1 present VC2 (e.g. modally)? If so, define protocol to let VC2 inform its delegate of some action. Then, when VC1 presents VC2, set VC1 to be delegate of VC2. That's much better than navigating through the view controller hierarchy and/or using app delegate (or any other object) to hold the properties being passed b/w VC2 and VC1. – Rob May 23 '17 at 16:53
  • `delegate` is definitely the better way in your scenario and also recommended by apple. – Maddy May 23 '17 at 17:01
  • 1
    @Rob u r champ man. I am following you since I have started development. – Maddy May 23 '17 at 17:03
  • This is possibly a duplicate of [Passing Data between View Controllers](https://stackoverflow.com/questions/5210535/passing-data-between-view-controllers) . See this [Swift answer](https://stackoverflow.com/a/31934786/5175709) – mfaani May 23 '17 at 17:35
  • @Rob, finally did a deep dive on Protocol/Delegates. Very powerful indeed! Thanks – Martin Muldoon May 30 '17 at 13:16

1 Answers1

1

First off, I've never got into the habit of using segue to pass information. What i would recommend is that you implement the delegate pattern whenever you need to pass data between two objects. Its a lot cleaner.

For instance lets say you wanted to pass data between LoginViewController and PostViewController:

protocol LoginViewControllerDelegate:NSObjectProtocol{
    func userDidLogin(data:String)
}


class LoginViewController:UIViewController {
    weak var delegate:LoginViewControllerDelegate?
    ...


    @IBAction func loginButtonPressed(sender:UIButton) {
        //Perform login logic here

        //If successful, tell the other controller or the 'delegate'
        self.delegate?.userDidLogin(data:"Some data....")
    }

}

class PostViewController:UIViewController, LoginViewControllerDelegate {
    func userDidLogin(data:String) {
        print("Got data from login controller: \(data)")
    }
}


//How you might use this
loginViewController.delegate = postViewController

One caveat to remember is to never try to have strong references between two objects i.e. do not have the objects hold onto each other or this will cause a memory leak.

1337holiday
  • 1,924
  • 1
  • 24
  • 42
  • You cannot make it `weak` unless it is a `class` protocol. Also, if it does have `weak` reference, I wouldn't make it an implicitly unwrapped optional (or else the app would crash if the `delegate` was `nil`). Safer to use `delegate?.userDidLogin(...)` syntax. E.g. https://gist.github.com/robertmryan/3d59608857f6b3797bf14dabb51a4a69 – Rob May 23 '17 at 20:30
  • You are right, i just took a look at some of my old code and the protocol indeed has to extend from a class, in my case i just extended `NSObjectProtocol` so i edited it to reflect that. Also made the update to the implicit unwrapped optional. – 1337holiday May 24 '17 at 14:36
  • Finally got up to speed on Protocol/Delegates. This worked like a charm. Thanks! – Martin Muldoon May 30 '17 at 13:17