Setting multiple delegates for passing multiple view controllers right way? - swift

So I'm using multiple delegates to pass trough data, but I don't know if it's the right way. I only want to maintain 1 main object to be sure that if a user exists/closes the app the edit data is saved when not in the VC1. By using the delegates now I'm sure the data is in the main object and all is well. Could you guys send me in the right direction and tell me if this is the way to go? Thanks in advance!
VC1:
Main object, holds all data that needs to be saved
Delegate for VC2
VC2:
Specific object overview from VC1
Delegate for VC3
Delegate function called -> PassDataToVC1(editsForSpecificObject)
VC3:
Edit's data from specific object. -> Gives
Delegate function called -> PassDataToVC2(edits)
Maybe even a 4th VC depending what I'm going to do.

What you're doing is basically correct for the architecture you have chosen:
If you have a rule that only VC1 knows the full data and can save it, then you need to pass changes in the data back to VC1.
If you have a rule that the way to pass the data back to VC1 is to use a protocol-and-delegate architecture, then you have to make VC1 the delegate for your protocol(s). There is nothing wrong with a single object (your VC1) being extended to adopt multiple protocols; that, indeed, is a standard Swift pattern.
However, I would argue that the reason this feels ugly to you is that those are not very good rules. I'll address them in reverse order:
Why delegation? In modern Swift, there are cleaner ways to pass data around. Modern app architectures are typically reactive, meaning that a handler of data is a publisher of the changes in that data, and the central store of the data subscribes to those publishers. Thus the data store can hear directly of any changes without the view controllers having to send those changes to anyone in particular.
Why a view controller? This is arguably the weakest point in your architecture. What business is it of a view controller to know anything about the data store and the mechanism for saving it? You should have a separate data store object retained by some securely persistent object such as the app delegate. This object stores and gatekeeps the data, and knows (or has a service helper who knows) how to persist it. You can use dependency injection to hand a reference to this object to every view controller — which also has the added benefit of making your code eminently testable. Even better, if you accompany this idea with the use of reactiveness that I outlined in the previous paragraph, you will have a clean "touch-free" architecture that just works, where every object does its own job and no other.

Related

Understanding the MVC design pattern in Cocoa Touch

Usually I just put together an app in any random way, as long as it works, but this means I don't pay any attention to any design patterns. My application currently makes extensive use of global variables (I carry an instance of my AppDelegate in every view controller to access properties I declared in my AppDelegate.h). Although it does what I want it to do, I've read this is not a good design practice.
So I want to start making my code "legit". However, I can't imagine my app right now without global variables. They are so important to the well-being of the app, but this must mean I'm doing something wrong, right? I just can't imagine how else I'd do some things. Take for example this:
You have two view controllers here, a SideViewController and a MainViewController. Using global variables, such as say if the entire application had one shared instance of SideViewController and MainViewController (appDelegate.sideViewController and appDelegate.mainViewController), I can easily communicate between the two view controllers, so that if I press "News Feed" in my SideViewController, I can tell my MainViewController to reload it's view.
I can't imagine, however, how this would be done if these were not global variables? If an event occurs in my SideViewController, how would I notify my MainViewController, in a way that is in accordance with design standards?
I can't imagine, however, how this would be done if these were not
global variables? If an event occurs in my SideViewController, how
would I notify my MainViewController, in a way that is in accordance
with design standards?
The same way you do it now, except that the SideViewController gets its reference to the MainViewController from a different place.
How are these two view controllers created? It's likely that it happens in one of two ways:
One of the objects creates the other. In this case, maybe the MainViewController creates the SideViewController.
Some other object, such as the app delegate or another view controller, creates them both.
In the first case, the MainViewController has a reference to the SideViewController as soon as it creates it. It can store that reference in one of its own instance variables, so that it can always send messages to the SideViewController that it created. Similarly, the MainViewController can give the SideViewController a reference to itself (that is, to the MainViewController), and the SideViewController can store that and use it in the future to talk to its MainViewController.
The second case is similar -- if the app delegate (or some other object) creates both MainViewController and SideViewController, that object knows about both objects and can configure each with a reference to the other.
In both cases, the objects in question are able to communicate with each other just as easily as they ever did and there's no need for a global variable.
What I've explained above is perhaps the simplest way to accomplish what you asked for -- communication between two objects. There are a number of patterns that can be used to refine the relationship between those objects to make your code even better:
delegation: Give SideViewController a delegate property, and define some protocol that establishes what SideViewController expects of its delegate. Implement that protocol in MainViewController. Make your MainViewController instance the SideViewController's delegate. SideViewController doesn't need to know exactly what type its delegate is -- it only cares that it's delegate implements the required protocol. This makes it easy to use SideViewController with something other than MainViewController if that opportunity arises, or to use it in a different project.
notifications: SideViewController may not even need a delegate -- it can simply broadcast notifications about certain events to any object that happens to be listening. This is particularly effective if more than one object might need to know about something that happens in SideViewController, or if the objects that care about SideViewController's actions might change.
MVC: Instead of telling MainViewController that something has changed, SideViewController just changes the data in the model. Whenever the MainViewController's view appears (or any other view controller's view, for that matter), the controller reads the data from the model and redisplays itself.
If you're interested, you might want to pick up a copy of Erik Buck's Cocoa Design Patterns, which explains these patterns and many others in great detail. Don't feel like you have to learn it all at once, or that it's all too much trouble. Learn a little bit at a time and see how it improves (or doesn't) your projects.

How to pass data between viewcontrollers

I have a fairly complex application at this point, and feel as though the way I am handling data is not up to scratch.
So I have started taking some steps towards making my app more MVC friendly.
The first of which, I have gone from having inline parser methods in all of my ViewControllers to creating a dedicated parser class.
Its not hard to call I just set up the class then call the initializer method I have made which I pass the data to for my request.. everything in my object class works sweet I get a whole bunch of return data from the server that I am parsing.. but then this is where I get abit lost.
How do I get that data back to the ViewController that called it? I have worked a little with protocols and delegates.. but I dont know how that would fit into this.
Here is an graphical example of what I am trying to achieve.
So as above View controller calls the initalization method of the object class which connects to the DB downloads the data, and then parses that data. The issue I am having is how do I then get that data to ViewController2..
what is the most appropriate and future proof way of doing this?
A custom -init method does wonders. For instance, I needed to instantiate and push a picker preloaded with the array from the previous screen, so I defined -(id)initWithArray:(NSArray*)array in the second view, then just called secondView = [[SecondView alloc]initWithArray:_population]; then pushed it. Remember to get ownership of any object you pass before it is deallocated and destroyed!
If you want to broadcast data from your object to all view controllers the good way to do this will be by notifications (NSNotificationCenter). You could also write a methods with completion blocks inside your parser object.
Try to send a local notification using NSNotificationCenter. Register your ViewController2 as a listener, then upon receiving the notification, call your data model (singleton!?) for the data.

Passing Several NSStrings to another view - Iphone

In my iPhone app, the user will be making multiple NSStrings. Once these are made, I need to pass them to another view completely in the app. How can i do this? All I know at the moment os I can't access objects or variables declared in one view, in another. Thanks.
One way would be to follow the MVC (model view controller) design pattern. Whichever controllers are responsible for your respective views can then store and retrieve the NSStrings from/to a common data model object.
As to how you can make the strings stored in an object visible to the outside, the easiest way is to use Objective-C properties to save you from writing the accessor methods yourself.
I hope this helps with your problem or at least gets you started in the right direction.
Place the strings in a data model object (the M of the MVC pattern), with accessor methods (getter and setters, which can be automagicly created by properties). Then create and place that model object in some central location, a controller common to all views requiring that data, or the appDelegate, a reference for which can be found from any view.
Josh,
I would add to the MVC thing, that still you can do this in several ways.
What I would do for example, is to make your other "View Controller" (MVC), to "observe" when does the user create a new string, and to fetch it accordingly. In that way you would reduce coupling and it will be a cleaner implementation.
Another way would be to create a "delegate" so that the First View controller, "notifies" or calls the delegate method that you created, each time the user creates a new string ( again reducing coupling )

Objective C Callbacks and Notifications

I'm new to Objective-C and not a full time programmer. I'm beginning to understand the Model-View-Controller design pattern for differentiating the UI from the model. So the user takes an action and the view controller sends a message to the delegate (model). But I'm not sure what the best way to send actions from the delegate back to the view controller.
For example, the user pushes a button, the VC messages the Delegate. That part I understand. Then the delegate takes action, and following that the delegate wants to update the VC (e.g., update a label).
So what I missed (or have forgotten) is how this gets done, while maintaining separation between the UI and the model. I suppose I can use the notification center. Or I think I can just have the view controller pass a callback to the delegate. Or maybe there's another choice I don't know of. Can someone give me a recommendation, please?
I think you're slightly misunderstanding the MVC paradigm. Models should never be delegates of views, since models should have no dependencies or knowledge of any view classes. Typically, a view sends a message to its delegate or target (if you're using target/action), which is usually a controller (often a subclass of UIViewController on iOS). The controller then accesses data from the model and can update any views that need updating. I'd recommend reading the MVC fundamentals guide for a more complete explanation.
Basically you're right, you could do all the notification-related things yourself (i.e. with NotificationCenter) but since we're talking about UI-Stuff here I would greatly recommend you to use IBAction-Methods and IBOutlet-Properties in your code which you can easily connect to UI-Elements respectively their Callbacks in Interface Builder.
A very basic introduction to this topic can be found here:
iPhone SDK Interface Builder basic training
i hope that it is not too basic tough, and that I could lead you on the right track.
First of all delegate is NOT a Model.
Model is something passive that only holds the data (DB, plist, array, dictionary etc.).
While delegate is some set of functions that exist in order to react to some events.
Delegate is more likely to be a view controller in your case.
The view controller should react to user's action.
If the button tap should display some data from your model in some label then view controller should do all the work (receive user's action, take the necessary data from the model and display it on the view...).

Save from viewController?

I have a very small bit of data that I would like to archive from my apps view. My question is, its far easier to save this data from the viewController, but should I really be pushing it back into my model and saving it there? BTW: I also need to do a quick load of this data when the app starts up.
Interesting question. If the data is not part of the model, then, no, the model classes should not take on the responsibility of saving it. If the data is only concerned with the view, then perhaps the view object should be responsible for saving, but that would break the rule that view objects should only concern themselves with display.
Seeing as we are in Cocoa territory, I think this task falls firmly to the ViewController. If you make sure that the ViewController is represented by an object (blue box, if I'm not mistaken) in Interface Builder, then you can take advantage of awakeFromNib to load your save data. BTW, it sounds like NSUserDefaults should be mechanism to use to do the archiving/saving & unarchiving/loading.