Reputation: 342
I was given a challenge to pass data back and forth between two (or many) unrelated (by segue) view controllers.
There are three view controllers, ViewController A
- ViewController B
and ViewController C
.
ViewController A
segues to ViewController B
and ViewController B
segues to ViewController C
.
I want to share data (such as text on a textfield) between ViewController A
and ViewController C
back and forth
Upon investigation I found four possible ways to achieve it :-
static
member, to store the data contained in textfield.NSUserDefaults
What would be the most logical way of achieving this? I would like to use one with least overhead. Thanks!
Upvotes: 2
Views: 1247
Reputation: 2941
The problem I see with delegation is when you want to send data to view controller A but that view controller is at the front end of the navigation controller stack and your view controller is 5 vc's down the line.
I would think it would messy to set up a protocol for each of the vc's lets say: A->B->C->D->E, where E where you are and you want to send data to A b/c A is going to make an api call to retrieve data and then that data now has to make it back to E.. so now you have to have another set of protocols to send the data all the way back.
If you are that far down the rabbit hole is might make send to get the first VC on the stack and set a public property (and send 'self'i..e E so maybe you can assign a public property to that VC for the data to consume.
Upvotes: 0
Reputation: 124997
Here are two solutions to the problem, both better (IMO) than delegation or the defaults system, and hugely better than singletons, static variables, global variables.
1. Pass the data through B
.
You've got a structure that's like this: A->B->C
, and C
needs some data that A
has. So the view controllers are not really unrelated, they're just not directly connected. A good strategy for handling this is to pass the necessary information through B
. That is, A
doesn't necessarily know about C
, probably shouldn't need to know. And C
doesn't need to know about A
either. From the perspective of A
, there's a job to do and a certain amount of information required to do it. A
should therefore provide all the necessary information to B
during the A->B
segue. If B
uses C
to get part of its job done, that's fine, but A
doesn't care about that. Likewise, C
doesn't know about A
or even B
-- all C
knows is that it's given some data to do a job. Since it's B
that's instantiating (by means of a segue) C
, it's B
's responsibility to provide the necessary information.
The same is true going in the other direction. If C
generates some data that A
will eventually need, B
should retrieve it from C
before C
goes away, and A
should retrieve it from B
.
The only reason you'd need to make A
a delegate of C
is if A
needs to find out about updates as soon as they occur. If that happens, though, it's probably a good indication that you should move on to the next option...
2. Use your data model.
It's easy to forget that the M in MVC is supposed to be an equal partner in applications. We often just let our view controllers manage all the data, and then try to figure out how to get the right data to flow through the view controller graph to the right places. That can make your application a lot less flexible than it could be: in a A->B->C
situation like the one you've got, you're suddenly prevented from inserting another view controller between B
and C
, for example, because the new guy doesn't know that it needs to pass certain data through from B
to C
.
The answer is to use a data model -- an object or set of objects that manage the application's data. If you've got data generated in one controller (C
in your case) that's needed by some other controller (like A
), that data must be important to the overall application and not just to a single view controller. That's exactly the kind of data that should be managed as part of your data model. If you do that, then you don't have to worry about passing a ton of different data to every view controller that might need it, or that (like B
) might need to pass it on to someone else. You only need to pass one thing -- a reference to the data model, or the relevant part of the data model.
Let's make this concrete and say that C
is actually a "settings" view controller, and that the piece of data in question is the user's name. A
needs to know about updates to the name so that it can display it properly. B
doesn't care about the name at all. So, you set up some kind of Model
class that includes a username
property. The Model
might be instantiated by the app delegate at startup, or by the root view controller A
, and a reference to the model is passed on to each view controller in the view controller graph. Now C
can set the username
property in the model when the user changes it. A
can read the same property to retrieve the data -- in fact, it can use KVO to find out about all the changes to the model that it cares about. A
doesn't know about C
or vice versa, and you don't have to bother with creating yet another delegate protocol just to pass some data around.
Upvotes: 5
Reputation: 1854
Without knowing more about your specific situation, delegation is usually the most common method of passing data between VC's. Delegation is the typical "pass data back" pattern.
Singletons are good in the scenario where what you really need is a manager class, something responsible for a certain state that is across your app. Singletons are less about "passing data back from a VC" and more about managing state.
Notifications are good if an event happens and you want a different class to process it or respond to it.
Upvotes: 0