Passing Data Between View Controllers in iOS: the Definitive Guide (Best Practices + Examples)

One of the places where most iOS developers make architecture mistakes is passing data between view controllers.

There are many ways to actually do this, but how do you know which ones are the best ones?

Many developers use the wrong solutions because they are quick and easy.

Quick and easy solutions often mean you will get into problems later. I know it first hand from many client projects and even my own apps.

When Apple published the iOS SDK in 2008, I made a little game for the iPhone. I read some Apple guides and started coding my app from there.

Soon I found myself puzzled by how to pass data from one view controllers should to another.

I was coming from Mac development where there was no such thing as a view controller. It was a new concept for me, so I did what I could with my little experience.

Some years later, I decided to improve my game by adding some new features. At that point my experience in iOS development had grown a lot. When I opened the project and I looked at the architecture of the app, I wondered:

WTF was I thinking when I wrote this?

You see, sometimes it is easy to look at someone else’s code and think they are bad developers. The truth is that everybody goes through an initial phase of poor understanding of the platform.

But what is the fundamental difference between the few developers that will become highly skilled and all the other copy and paste developers?

  • Good developers know they lack knowledge and take the time to grow it.
  • Bad ones never bother, they go on with the little they know, trying to hack together something and calling it a day.

Do you want to be be a proficient iOS developer? Then you have to know the architecture ideas behind view controller communication.

I have already wrote about the MVC pattern in iOS and how an iOS app is structured. In those articles I have treated view controller as separate independent entities for simplicity, but they are not. They constantly need to communicate and pass data back and forth, for any non trivial app to work.

There are different ways to enable communication between view controllers. In fact, if you look at this question on Stack Overflow (which is among the most frequently asked about iOS), you can find all of them.

But are they all good?

Here are all the ways in which you can pass data between view controllers:

  • when a segue is performed
  • triggering transitions programmatically in your code
  • through the state of the app
  • using singletons
  • using the app delegate
  • assigning a delegate to a view controller
  • through unwind segues
  • referencing a view controller directly
  • using the user defaults
  • through notifications

A few of them are the best practices of view controller communication.

Others, though, are not so good. Like the ones I adopted in my little game (I was referencing view controllers directly).

What makes the best practices what they are? They respect the principles of good software architecture and common design patterns.

I checked again recently Apple’s guide on view controllers and the information was in there all the time. But Apple’s documentation is a bit terse. When I read it years ago I could not absorb all the concepts.

So let’s have a look at hot to pass data between view controllers in more detail.

There are two directions in which a view controller can pass data to another view controller. For each one of these there are different techniques:

  • forward, to the destination view controller of a transition
  • backwards, to a view controller that was on the screen before and to which the user is will go back at some point.

So, how do you pass data between view controllers in Swift?

Let’s explore all the examples.

Passing data between view controllers connected by a segue

The most common situation is when a transition happens through a storyboard segue.

Passing data between view controllers connected by a segue

Separate view controllers in a storyboards have no knowledge of each other. The only connection they have in the storyboard is the segue itself. This is exactly the mean through which they can communicate.

When a transition is triggered and a segue is performed, the prepare(for:sender) method is called on the source view controller.

The triggered segue, which is an object itself, is passed as a parameter to this method. Through its destinationViewController property the source view controller can access the destination view controller.

Let’s look at an example of this.

Let’s say we have a Data struct that we want to pass from an SourceViewController to a DestinationViewController

First of all we have to make the DestinationViewController able to receive such data

This property needs to be declared as optional because when the view controller is initialized it will not be able to receive this data in its initializer. I talked more about these initializers and other common methods in my article on the lifecycle of a view controller

We then pass the data from the OriginViewController to the DestinationViewController in the prepare(for:sender:) method of SourceViewController:

Keep in mind that this method gets called for all segues that originate from a view controller.

To distinguish between different segues when there are more than one, you can either use an optional binding like in the example or the identifier property of the segue. The identifier is a string you can set for each segue in the storyboard.

Passing data between view controllers without a segue

There are some cases when a transition to a new view controller does not happen through a segue, but programmatically.

Passing data between view controllers without a segue

This might happen when the destination view controller:

  • is in a different storyboard than the source view controller (although since Xcode 7 it is possible to use storyboard references, which enable segues between separate storyboards)
  • is in a nib file
  • does not have an interface file at all and creates its view hierarchy completely in code.

In this case, the passage of data is straightforward. Since the source view controller instantiates the destination view controller, it has a direct reference to the latter.

Let’s see as an example, the modal presentation of a view controller that comes from a nib file:

As you can see, the view controller creation and the passing of data happen at the same time.

Passing data between view controllers inside a tab bar controller

In the cases we saw above, the source view controller gets a reference to the destination view controller somehow.

There is a special case where this does not happen: when you use a tab bar controller.

Passing data between view controllers inside a tab bar controller

When you switch between the tabs of a tab bar controller, the contained view controllers do not get a chance to be connected, and no segue gets triggered.

This is not necessary though. View controllers in a tab bar controller usually have no relationship, since they deal with independent parts of an app. There is no source and no destination.

This means that they don’t need to pass data to each other.

What these view controllers do is read their data from the state of the app. You can refer to the next section to see how to read data from the state of an app.

Passing data backwards through the shared state of the app

The first way to send data back to a previous view controller is indirectly through the shared of the app.

Passing data backwards through the shared state of the app

View controllers usually share references to the model containing the current state of the app. The model of the app is usually passed forward between view controllers in the ways we have seen above.

To pass some data back the destination view controller simply updates the model, without needing any reference to the source view controller.

When the previous view controller comes back on the screen, it just updates its user interface reading the model again, to which it also has a reference. This usually happens in the viewWillAppear(_:) method (read my article on the lifecycle of a view controller for more on this)

This is a common and easy way of passing data backwards, since it requires little code and no connection between the view controllers.

Passing data to the previous view controller through an unwind segue

If you use storyboards in your app, it makes sense to go back to previous view controllers through unwind segues.

Passing data to the previous view controller through an unwind segue

If you are using a navigation controller, there is no unwind segue. The user goes back to the previous view controller by tapping on the back button and the navigation controller takes care of everything. In this case you use either the state of the app as we have seen above, or you use delegation, as we will see below.

You use unwind segues usually when you present a view controller modally.

Unwind segues work a bit differently than forward segues. To connect two view controllers through an unwind segue, you need to create and unwind action in the view controller you are going back to. You can see how that works here.

When the segue gets triggered, prepare(for:sender:) gets called in the source view controller as usual. Here you save the data you want to pass backwards in a property that the destination view controller will access to read the data.

Then the unwind action gets called in the destination view controller. Here, the destination view controller reads the data from the property of the source view controller.

You don’t necessarily need to pass data back this way. You can pass data backwards through the state of the app even when you use an unwind segue. In that case you would:

  1. Save the data in the state inside of the prepare(for:sender:) method of the source view controller
  2. Read it in the viewWillAppear(_:) method of the destination view controller, as we did above

Passing data between view controllers using a delegate

Sometimes the methods we have seen above are not enough.

  • The data to pass back might be temporary and thus not belong to the shared state of the app
  • When going back inside of a navigation controller, no unwind segue is triggered
  • We might to pass data backwards at a different moment than the one of the transition

We need to create a connection between the source and the destination view controller.

The solution could be to pass a reference forward using one of the methods we have seen above and then use that to communicate backwards.

But it’s not so simple.

Passing data between view controllers using a delegate

The problem is that we cannot reference the previous view controller directly. Read the section below to see why.

The solution here is delegation.

What we need is a delegate protocol for the destination view controller. When the destination view controller needs to pass data back, it does so to its delegate.

The delegate property needs to be declared weak to avoid strong reference cycles. See this article for more details on weak and strong references.

The source view controller then conforms to such protocol to receive the data. Then, when passing data forward it has to set itself as the delegate for the destination view controller.

The advantage of this approach is that the destination view controller does not need to know which object is the delegate. As long as such object conforms to the protocol, it’s fine.

Do not reference directly the previous view controller

The protocol approach could be substituted by direct knowledge about the previous view controller.

In this case we would lose the advantage of the protocol. The destination view controller now has specific knowledge of the source view controller.

What happens when we change the interface of this controller? Also in the flow of an app, a view controller can be reached through different paths and thus through different source view controllers.

This clearly does not work. A view controller would need references to all the view controllers that could possibly come before itself.

Our destination view controller’s code breaks and we have to change it. This is because we are introducing to much coupling between the two classes.

As Apple says in its own view controllers guide:

Always use a delegate to communicate information back to other controllers. Your content view controller should never need to know the class of the source view controller or any controllers it doesn’t create.

Do not use a singleton to share the app state

Singletons are an abused programming pattern that, especially in iOS, gets used for anything.

The reason a singleton is very easy to create and use. It looks like a perfect solution.

But it’s not.

On the surface this approach looks similar to the example of passing the model between controllers we have seen above.

The problem is that singletons can be accessed directly from anywhere in the app. You have no control. Singletons introduce a lot of coupling in your code and make your objects hard to test in the future.

You can search on Google for “singleton anti-pattern” for more information about why singletons are bad. For example, you can read this Stack Overflow question.

Do not use the app delegate

Using the app delegate is the same as using a singleton.

Although technically speaking, the app delegate is not a singleton itself, it can be considered one.

This is because you access the app delegate instance through the shared UIApplication instance, which is itself a singleton. So this creates the same problems discussed above.

This line should never appear anywhere in your code:

Do not use UserDefaults

The purpose of UserDefaults is to store user preferences that persist between app executions.

Anything stored there will stay there unless explicitly removed, so it is not a mechanism to pass data between objects.

Also, you can only write simple data types in the user defaults and there is no compiler check on the data you write there. This means that some code at some point might change the format of such data and break code situated elsewhere in your app.

Finally, it’s again like using a singleton, because you usually access the user defaults through the shared instance of the UserDefaults class.

In general, your app should have a single access point to the user defaults, through a custom class that every other part of your app uses. Refer to the app state example above to do this.

Do not use notifications

Notifications are a way to spread information to multiple objects to which you might not have direct access.

As such it can work also for passing data between view controllers. That does not mean you should use it for this reason.

Notifications create too much indirection and make your code hard to follow. When you post a notification you cannot be sure which objects will intercept it, which might lead to unexpected behavior in your app.

I have seen codebases haunted by bugs caused by objects receiving a notification when they should have not.

Notifications can be useful sometimes, but in general communication between view controllers should be done using the mechanisms we have seen above.

Should view controllers know about each other at all?

What we have seen are all the standard solutions used in iOS to pass data between view controllers. Many of these solutions require view controllers to know about other ones.

But should view controllers know about each other?

Since the flow of an app can change at any moment and many paths can lead to a single view controller, it might seem that we are introducing too much coupling between our view controller classes.

After all each view controller should only take care of their own screen, shouldn’t it?

That is indeed true. You can use a more advanced and non standard architecture that includes coordinator objects that take care about the flow of an app.

That is exactly how the VIPER design pattern works, when you look behind all its jargon.

But although they are not so advanced, the techniques shown in this article are solid and widely used among iOS developers, so there is nothing bad in using them if you are not ready to adopt more advanced practices in your project.

I used myself in many projects. You can switch to a more complex architecture when you really start understanding their need from experience.

Conclusion

As we have seen there are many ways to pass data between view controllers. Some of them follow the pest practices, while others seem to be easy at first, but only create problems later.

If you want to see how these techniques are used in a real app, I have a free course on building professional apps that will guide you through all the steps.

Learn how to use view controller communication in a real app in my free course

100% privacy. No games, no spam. Unsubscribe at any time.

Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+
  • Darren Gillman

    Great blog post. These concepts always seem simple when you know them, but so easy to get wrong though. Good to have them clearly explained.

    How do you handle async though? For example, logging in to a web service and then needing to get some sort of authentication token back which is subsequently used by multiple objects that are waiting on this token before they can do anything productive? This is where previously I’ve tended to use notifications, as they cope with the 1:many aspect and kicking off multiple different actions nicely.

    (Now that you’ve made me think about it, would it be better for the callback to update a data field in the model and using observers to pass the info on? Or is this effectively just another form of notification?)

    • I didn’t talk specifically about notifications here because this article was about how view controllers communicate with each other and not how they communicate with the rest of your code.

      In case of asynch callbacks notifications would definitely be an option and I will talk about those in the future. But I tend to use them sparingly and only when necessary, due to them being hard to follow mentally. Every time you post a notification you don’t know which objects will intercept it and in which order. I have seen many code bases plagued by bugs caused by this.

      In some cases you need notifications, but I discovered that you do much less than you might think of.

      For example, in network communication, most of the times the view controller that initiates a request is the only one that needs a callback. In that case my preferred method is to use a closure for the callback. Sometimes a delegate protocol might make more sense, assuming your network controller instance is not shared among different controllers.

      In cases where you need to update the global state of the data, I would still go for a single callback at the origin of the network request. The callback then takes care of updating the global state and every view controller updates its UI as soon as it comes on the screen (through viewWillAppear(_:)).

      The only scenarios that come on top of my mind at the moment for the use of notifications are these:

      – The callback for the asynch call (or a timer that fires) comes at a time where the user has navigated away from the screen where that was initiated, but you still want to present a result to the user (through an alert, for example). In that case a notification might be used to trigger the presentation of this alert, regardless of what view controller is on the screen at that moment and what the user is doing.
      – An event is generated without a user action that generates it. For example, this might happen in a multiplayer online game, where the server sends periodical updates without your app requesting them. Or another example is the app changing state (going to the background, etc.) which might happen at any moment.

      • Darren Gillman

        Yeah, that all makes sense.

        Thinking through my example of an authentication token again, it’s probably slightly false as I should be holding the data in a single ‘user’ object rather than holding it in multiple view controller. Which then leads to the interesting question whether it is right for the initial view controller to instantiate the user object or whether to do it from the AppDelegate, and how to then pass its reference to other parallel VCs,?

        Thanks for taking the time to go off at a slight tangent. It’s always good to think through these things theoretically, so hopefully I then adopt the good practice when it comes to actual coding. Thanks again.

        • I spoke a bit about this in other articles and I go more in details in my course, but the overall idea is to keep state in a separate object that then gets passed around view controllers. As for where to instantiate it, I definitely do it from the app delegate and then pass it to the initial view controller. Each view controller then passes this object to the next one.

  • Martin van Spanje

    What are your thoughts on passing data back using unwind segues?

    https://developer.apple.com/library/ios/technotes/tn2298/_index.html

    • That is a good question.

      I forgot to mention it in this article, since it’s not one of the most popular ways. It’s not even included in a guide, but just in a separate technical note, although the introductory tutorial from Apple uses it (in the “Implement navigation” section): https://developer.apple.com/library/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/index.html#//apple_ref/doc/uid/TP40015214-CH2-SW1

      In my opinion it is indeed a valid method.

      At his basic use it is a way to pass data back without affecting the model of the app or creating a delegation infrastructure. Beware though not to fall into the trap of referencing the previous view controller in prepareForSegue(_:sender:), since that would be equivalent to what I explained in the section of what not to do.

      The correct approach is the same you can see in Apple’s tutorial: set a local property with the data you want to pass backwards, then read such property from the unwind action. If you unwind to a different view controller than the one you came from, this is the only way to do it apart from changing the model. In this case delegation would not work.

      At the moment I am not sure I like it much, since the flow is a bit clearer in the other two cases. But I don’t dislike it either. I will think a bit more about it an maybe update the article.

      Nice catch, thanks for asking.

  • ShadowGarden

    I have a fundamental question about view controllers. I don’t use Interface Builder, so I implement all UI views programatically including auto layout constraint settings. And I actually found out that I don’t use view controllers at all (except the initial/built-in view controller) because I don’t really get the concept what they are for.

    For example, if I want to add a table view, I just create a UITableView() programatically and add it to a parent view. Why do I need to have a UITableViewController? I don’t even know how to incorporate it into my code. And what’s the benefit to use one?

    • On the first topic: using or not using Interface Builder. It is indeed possible to do everything in code. I would ask myself why though. IB is there to make your life easier in a lot of tasks and strip away a lot of code from your app. There are some reasons why people don’t use IB, like large teams where it gets hard to work together on a storyboard, but that does not seem to be the case for you. Why are you doing it? Just because somebody told you to do so? Or because you don’t want to learn IB? Feel free to then continue doing things in code if you prefer so, but in my opinion you need a valid reason to give up all the help IB gives you.

      Second topic: view controllers. These are the fundamental building blocks of an iOS app. Roughly speaking, a view controller represents one screen of the app and manages its resources.

      What you are doing is adding everything to the first screen. This means that all the resources get allocated there and you keep all of them in memory all the time. Also, you have to code yourself all the animations that iOS gives you for free.

      View controllers are a large topic, but a fundamental one you must understand for iOS development. What you do is possible, but goes against the platform design and will create you all sorts of problems down the road.

      For a starter, you can read the other articles I have written on the topic:

      http://matteomanferdini.com/the-concepts-at-the-foundation-of-any-ios-app/

      http://matteomanferdini.com/how-to-structure-the-code-of-ios-apps/

      http://matteomanferdini.com/the-common-lifecycle-of-a-view-controller/

      http://matteomanferdini.com/understanding-the-core-architectural-principles-of-ios-development-with-a-practical-example/

      • ShadowGarden

        Thanks for your detailed reply. Really appreciate it.
        About IB, I understand your points. I also researched earlier if I should use it or not. The conclusion was the same as yours. One should take advantage of what IB offers and Apple encourages people to do so. I did try to learn IB, however maybe I am an old school type. I have been coding in C/C++ for many years but I was mainly coding on system level instead of UI level, therefore when I come to UI, using a tool like IB is very painful for me. For example, now I am coding a table view with custom cells. When the device rotates, I want to change the layout of the views arranged in a cell (without reloading the table). I can do this freely in code. However, when I think of using IB to do the same, I just can’t get it. Things become complicated to me.
        About view controllers. I also understand your points for a view controller representing one screen and I am actually adding everything onto it. But the thing that really confuses me is not UIViewController representing a screen. But as in my original question, when adding a table view to a screen, why do I need to have a view controller (UITableViewController) for this table view? To me, it’s a subview for the first screen. I still can make a separate class to handle the table view and everything goes fine without a UITableViewController. From my understanding, if I go through the typical route by adding a table view to a UI view screen via IB, I will be using UITableViewController. This is something I don’t get and maybe I miss or misunderstand something.

        • IB might take some time to get and indeed it does not allow you to do everything you can do in code. For those cases I just use a mixed approach.

          Regarding view controllers and table views, there are many points in your question.

          Yes, you can and indeed you should add the table view to the view of the first view controller, if that table view is on the first screen. A table view is a view and like any other is part of the view hierarchy. Each view controller has its own view to display the interface for the screen.

          If it is on another screen, though it belongs to another view controller. Views are only visual element. A view controller is responsible for handling the flow of data to and from the views.

          UITableViewController actually does not do much and is not required. You can have a table view with a simple UIViewController. UITableViewController is just a subclass that packs a couple of common tasks you do with table views, but you can do without.

          This is a complex topic, so I can’t cover it all in a comment. You can check Apple’s guides:

          https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/index.html

          https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/Introduction/Introduction.html

          • ShadowGarden

            Sure, thanks for the general direction. I will go through more documents and your articles to pick up more.

            Thank you very much.

  • Walter Marchewka

    I have read through your guide on passing data between view controllers. I am using a delegate and am able to pass data to and from two view controllers. However, what if i wanted to pass live data, such as a timer? For instance, say i have a view controller that starts a timer that counts every second. Now on view controller one, i have a label that reflects that up counting timer. Suppose i wanted to send that continuous counting clock to another view controller? Right now, i only get the value when the segue is called because the connection between the viewcontrollers only exist for that instant that prepareforsegue is called. How could i display the up counting clock from viewcontroller 1 on viewcontroller 2? Thanks!

    In the comments someone posted something similar with async communications. What am i actually designing is an IOS app to communicate with Modbus TCP to a microcontroller. Since one view controller will be constantly polling the microcontroller, i want a separate viewcontroller to display a graphical representation of the microcontroller and the LEDs that will be hooked up to it off of the output pins. I need to pass the data that returns from the microcontroller and pass it from the viewcontroller that is polling the unit to the view controller that is representing it graphically.

    • This is a different problem than view controller communication. Remember that responsibility of view controllers is to manage a single screen, not more.

      Since this timer affects the app globally and more than one screen, it does not belong inside a view controller in the first place. It is better placed inside of another object. After you do this, there are two solutions to get the information to the appropriate view controllers that need to display it. Notifications and Key-Value Observing (which I still didn’t have the time to talk about on this blog)

      1) Every time the timer fires, the object that contains it posts a notification. The view controllers that need this value, listen to that notification and update their own interface when it’s posted.

      2) Every time the timer fires, the object that contains it updates a public property. This object can be passed around to different view controllers, which observe this property through KVO

      Personally I would go for the second solution, since architecturally it is better. It requires a bit more code than the first one, though.

  • Rob Soto

    Your a legend! Passing objects backward through the protocol is super easy and convenient. When I updated to iOS 9 all of my unwind segues no longer worked properly. Since I only needed to unwind one view controller I was able to use self.navigationController.popViewControllerAnimate(true) and pass the objects through your method and is worked perfectly :)

  • Nolan Regier

    Matteo, I’m having some difficulty passing data through the model between view controllers. Any suggestions on a good tutorial or description?

    • Not that I can think of, sorry. What is exactly your problem?

      • Nolan Regier

        I’m building an app that will be used to calculate the volumes of cement and chemical, and the procedure required for a given hole. To make this work there will be 5 or 6 views with UI required to be completed by the user which would then be used for the calculations in the model and populate a summary view which could then be printed or sent as a PDF. The issue I’m having is that each view needs to instantiate it’s own instance of the model for which certain properties need to be shared with other views. Any help point me in the right direction would be great.

        • So, by 5 or 6 views I suppose your app would have 5 or 6 screens, which in iOS means an equal number of view controllers.

          To keep shared state, you should create a class, let’s call it StateController. This will contain all the state view controllers need to share with each other.

          You then create one instance of this class in the initial view controller of your app and then pass this single instance forward to other view controllers with the techniques I described above.

          • Dennis Major

            Is there any problem with creating a struct with static vars and static funcs as a means of maintaining state for the app’s various view controllers versus instantiating a StateController and passing that object around to any of the app’s view controllers in need of state information?

            What I’m proposing has the “feel” of a singleton – so maybe I should be instantiating a struct but I’m having difficulty understanding why it is necessary to instantiate versus using a structs static vars and funcs.

          • The problem is not in the way you implement the singleton itself, the problem is in having global shared state in a place that can be accessed from everywhere. Wether you do this through a class that returns the same instance or other means, it does not matter.

            The problem in this is that all the code that accesses that singleton becomes coupled to it. This makes it very hard to test such code. Moreover, unexpected changes to shared state are one of the main causes of bugs.

            You can read more about it here, for example: http://stackoverflow.com/questions/12755539/why-is-singleton-considered-an-anti-pattern

          • Dennis Major

            Thank you for the comments and link Matteo. Helped me understand that what I wanted was to create properties with a global get operarion and a fully constained set operation.

            I was able to do so with struct computed static vars with tuple set param that limits the set operation to one class and as well populates a global get only staric var each time the constained computed var is updated or set.

            Have yet to try it but I should also be able to constain set operation to one object instance if that’s a design requirement.

            As far as I can tell this setup is easily tested and the recievers of the get var see it as a consistent black box data source while the constainted set computed var has a fair amout of flexibility for modifying and constaing how the get output is generated.

            So constained and flexible set data and global and consistent get data.

            Given my limited design pattern experience I could be creating hard to maintain code but it doesn’t feel that way. I think it’ll be easily understood and easily modified if that was required six months doen the road.

  • Nolan Regier

    Excellent, thank you very much for the help. You’re articles are excellent and well written. Learning iOS development has been rather frustrating and it’s good to have a resource that is clear to follow.

  • Karina

    Hi Matteo, I’m trying to build an app news that when I clicked in and article opens a detail view that have title, image, date and also a webview with another related articles, when I click on each related article I have to present this data in the same view controller (update the article data) how can I do this, like making a transition to the top, not a new controller, the same controller? I’m making the request data throug a model news and with a delegate notify in the same view that I have the new article updated info but I can’t present it in the same viewcontroller. Appreciate your help!

  • Huy Vu

    For Xcode 8 and Swift 3, in OriginViewController class, when you pass data through delegation, change:

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

    to

    override func prepare(for segue: UIStoryboardSegue, sender: Any?)

    • Indeed. In Swift 3 many methods in the SDK have been renamed to follow the new naming guidelines.

  • Lionel Chaumeau

    Interesting tutorial.
    I’m having problems putting it to use though, concerning passing data back through delegation. When and how to fire passDataBackWards().
    I’ve tried firing it in the override of viewWillDisappear() (in the destination Controller), but it doesn’t work.

    • That should work. What is the problem you have?
      I would check with the debugger. Putting a breakpoint on that line should help you finding the reasons.

      • Lionel Chaumeau

        Thanks for the quick answer.
        Ok, sorry, my comment was not very precise. i’ve put a break point in my equivalent of :
        func passDataBackWards() {
        let data = Data()
        delegate?.doSomethingWithData(data)
        }
        but it doesn’t go through there (I have 2 segues, one to go to the destinationView, the other one to go back to the originalView)

        That’s why I’ve tried to encapsulate the call to the delegate into viewWillDisappear:

        override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if self.isBeingDismissed {
        let data = Data()
        delegate?.doSomethingWithData(data)
        }
        }
        but the data is still nil in my originalView… besides, I’ve put a breakpoint inside viewWillDisappear, but it’s not called when I go back to originalView…
        I’m quite at a loss to understand in what you show here how passDataBackWards is called…

        • The strange part here is viewWillDisappear(_:) not being called. That should be called when both going forward and backwards.

          What are you using to transition? A navigation controller? Or it’s a modal presentation (it should not make any difference anyway)

          Pay attention to self.isBeingDismissed. The documentation does not say anything but I assume it will be true only when using modal presentation and not inside a container like a navigation controller.

          • Lionel Chaumeau

            I see what you mean. Indeed, it’s strange that viewWillDisappear is not being called. Maybe because I segue from 2nd view to 1rst view ?
            What I do is use a stateController that I declare in each view

            var stateController : StateController?

            and I use you tuto to try to pass this controller from one view to another, to keep the state of my App (and to keep the calculation done by the App alive, whichever view is called).

            Here, when I go back to 1rst view, stateController is nil, even if I have in 1rst View Controller:

            func doSomethingWithData(stateController: StateController) {
            self.stateController = stateController
            }

            It works when I use the segue method you give at the beginning of the tuto (segue from 2nd View to 1rst View) but i don’t manage to implement the code you give to do it though delegation… i’d love to, though, because it lessens the dependency between the views

          • Passing the StateController forward is correct. What I still don’t get is why the viewWillDisappear(_:) is not called.

            What kind of segues do you have between the view controllers?

          • Lionel Chaumeau

            Show ones.
            What I don’t understand in your tuto is how the passDataBackWards func is called in your exemple.

          • Lionel Chaumeau

            Ok, I understand the problem now… I use several checks on properties of the stateControlleur in 1rst view Controller viewDidLoad(). Apparently, the viewDidLoad of this view fires before viewWillDisappear of the 2nd view controller. So I had the error before viewWillDisappear was called…

          • Ah, yes. Good find. There is no guarantee on the order in which different lifecycle methods are called across different view controllers. Different containers have different behaviors and load view controllers at different moments. You can only assume the order of the methods in a single view controller.

          • Lionel Chaumeau

            Very tricky indeed, so much that I didn’t manage to apply this exchange through delegate AND make the view display the data exchanged (I tested and it’s very strange: the first view controller gets the data but the view doesn’t display it)…

            But I realized that my need is broader than exchanging data between views. I need an object that can exist all through the app, and stock some data and multithread (through GCD) calculations, independently of the views…

            Well what worked for me is close to the model example you give:
            create a stateController following the Singleton design advised by Apple:
            class StateController {
            static let sharedInstance = StateController()
            ….
            }
            It create one instance of StateController that is thread safe (Apple: “n Swift, you can simply use a static type property, which is guaranteed to be lazily initialized only once, even when accessed across multiple threads simultaneously”, https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#singleton)
            I then get it whereever I want throughout the app:
            class ViewController: UIViewController {
            var stateController = StateController.sharedInstance


            }
            And it works just fine.
            Thank you fro the time you took to answer me and for your tuto, it really allowed me to progress and lead me to ask myself the right questions
            cheers

          • Lionel Chaumeau

            I know that in you tuto you specify to not use singletons, but I don’t really understand why you consider it not to be a good practice.
            Specially when you write “Singletons introduce coupling in your code and make your objects hard to test.”
            I have much less coupling with a singleton stateController than with the segue technique or even the delegation one (both are view dependant), and I can easily test my stateController at any moment… I must have missed something in your arguments.

  • captaink99

    Matteo great article…

    But tell me prepare for Segue doesn’t get called with ViewControllers in a Tab Bar.

    What would the code look like then?

    • Indeed, prepare(for:sender:) does not get called in case of relationship segues (for example tab bar controllers or the root view controller of a navigation controller).

      In this case there are different solutions, depending on which view controllers you want to communicate.

      I assume you want the view controllers in different tabs to communicate with each other. For this you can set a delegate for the UITabBarControllerDelegate and enable communication when the tab gets changed, or subclass UITabBarController.

      But this would be atypical. Normally view controllers among tabs don’t really communicate directly. What they usually do is share the state of the app and update that one, so communication is indirect.

      If you really need to have different tabs communicate directly I would say your app might have a strange user interaction which should be rethought. It is not a normal UX paradigm in iOS.

      • captaink99

        I injected dependencies from my login controller to my firstTabViewController and that works fine – created a custom function which gets called.

        But I now want to pass that object to the secondTabController.

        So I realise prepare for isn’t the right way. So how would I implement this?

        • There are two ways.

          The view controllers in a tab bar controller all get instantiated immediately. So you can do it at the same time you pass dependencies to your firstTabViewController. I assume you are accessing the viewControllers property of UITabBarViewController. Just loop through each view controller in the array.

          The second way is to set a delegate for the tab bar controller (you can subclass it and set itself as its own delegate). Then pass the dependencies in the tabBarController(_:shouldSelect:) method.

          • captaink99

            wow… thanks Matteo… you just saved me a lot of time. Actually the penny dropped when you mentioned that all view controllers in a tab bar get instantiated immediately. Your explanation was excellent

  • Jasper M. Goce

    Great read!. Its funny cos I did all of the things you listed on the DONTs :D I will never do it again. I promise hahaha thanks.

  • Armand van der Zwan

    Tip:
    When passing a Core Data ManagedObject to the next ViewController it is better to pass the ObjectID instead of the real ManagedObject. Let the next ViewController get it from the context itself by that ObjectID. Better for Testing also!

  • Jinshi Feng

    Hello Matteo, I am from China. Thank you very much for these great articles. I have one question. In the section above —Passing data backwards through the shared state of the app, you mentioned ‘ shared state of the app’. I try to understant what is ‘ shared state of the app’? Could you give more introduction about it? Is there any related artices I can read?

    • By shared state I mean whatever data the is shared across the app and is in memory. For example, if you have a to-do list app, the shared state could be the list of the to-do items.

      The shared state is kept in memory and usually different parts of the app access it. To continue with the to-do list app, let’s say that the items can also have a date. An app could have one screen that shows the items in a list, and another screen that shows them in a calendar. But the data is always the same, only its representation to the user is different.

      This data is usually kept in a place that different parts of the app can access. This is what I mean by “state”.

  • cleverClosure

    Thanks for your work. I have a question. What if I need to pass the data from AppDelegate to TableViewController, and TableViewController is embedded in NavigationController which is embedded in SplitViewController which is embedded in TabBarController? Do I need to subclass every container viewcontroller and pass the data trough this hierarchy?

    • That is one option.

      Another one is to do all this in the AppDelegate. You would end with a bunch of if statements though, and that code would be very brittle and break at any change in the navigation of the app.

      The best solution, albeit more complex, is to use VIPER / coordinator objects. I put links to those in the article.

  • Link missing:
    “You can see how that works here (link) “