I have an NavigationController based app where the data model is stored in the appDelegate after being fetched using CoreData. The views that display the data all have a pointer to appDelegate so that they can query the model for the required data. They then call methods in the appDelegate in response to user selections.
My question is, doesn't the MVC pattern optimally hide the data from the view? Would it be best practice for the appDelegate (in this case serving as model and controller) to supply the data to the view, and for the view to simply send a notification when there is user input? That would eliminate the need for the view to maintain a pointer to the appDelegate.
You're correct to worry about AppDelegate taking on this role. AppDelegate is an easy place to dump stuff, and it quickly becomes overwhelmed with roles. As you note, it's playing data model, data controller and application delegate. If you're getting to the AppDelegate using [[[UIApplication sharedApplication] delegate], it's especially a problem because it makes it very hard to reuse the view in other programs. It's less of a problem if your view has a delegate ivar that just happens to point to the AppDelegate, but could easily point to some other object.
The view often should have a delegate that it passes UI events to. See UITextField and UITextFieldDelegate for a good example pattern. Views generally don't post NSNotification for this kind of stuff. Conversely, model classes typically work best without delegates in my experience.
I am a huge believer in NSNotification. My programs use them for almost all data that moves up from the model layer. But for actions that move down from the view layer, delegation and direct method calls typically work best.
Its not your view that accesses the data. The controller should be the link between the data and the view. If by view you mean the controller, then that's perfectly fine and basically what MVC is all about.
Related
I'm new to programming, iphone application programming in specific. After reading a bunch about MVC I decided to give it a try in a small application. As to my understanding, MVC works like this:
Model: data, manipulating data, retrieving data.
ViewController: formats data from the model (NSDate to specific style), etc.
View: the actual gui.
If this is indeed a correct formulation of basic MVC theory, my confusion lies in how data is passed between the model, VC, and view. Example: if I make calls to twitter and get the data in the model, how do I (correctly) pass this information to the VC for further work. I know that between the VC and View one mostly uses IBOutlets. The Model is my real problem.
In my last app I made an NSString variable in the app delegate so I could access that data from any class. However, I read that this is not the best approach when the app becomes complex because the delegate is in charge of starting, ending the app, not holding data.
I've read of delegation methods, singleton's, NSNotification (which I've used to call methods in other classes). The problem is that I don't really understand how to use these techniques to pass data from the model to other views.
Please let me know if my question is unclear.
If you think about reusability, the main components that can be reused again are your model objects and view objects. They can be moved to different apps and still used properly. Your view controller is what is really specific to your app and where most of the app logic lies.
So in your example, you could have a twitter object that stores information and tweets from a user perhaps. You would create that class with all its functions separately within its own .h and .m file. Then in your view controller, instantiate the twitter class with data that is retrieved and begin using it from within the view controller.
Your view controller is actually retrieving the data but your model object is the one maintaining the data. In this way, you can pass on the model data with your twitter object to other view controllers.
Control over the application resides in the controller, so it is the object that will retrieve or save persisted data, update views with that data, and handle various events. Consider it the glue between the model and the view!
For example, if you were to click on a button to open a new modal view, you'd handle that event in your view controller. In the method that responds to the clicked button, you will create or access the new view controller and present it using presentModalViewController:animated:. If that new view and controller needs data that your current controller has access to, you could set a property in the new controller to refer to the object.
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...).
considering good design, is it better for each view controller to manager their own connection / networking / loading, or to centralize it in the app delegate, or a separate object?
Context:
I have a multi-tab app, each with a navigation controller, and a number of view controller below. Each view controller is doing networking loading XML and images. Currently, i have it setup that it calls to the app delegate to get the xml asynchronously, processing it, and then calling back the top view controller to display the info, and then launching a separate process of loading the images into an array, and sending callbacks for when each is loaded.
From an architectural view-point, is it better to have more networking code in each of the view controllers or calling back to the app delegate?
Ideas / opinions?
TIA.
It's going to make much more sense to have this in each View Controller, I think. The way you've got it set up now sounds a bit weird - you must either be using delegation so that the App Delegate can speak to each view controller, or you have a ton of references to your View Controllers in your app delegate which you probably don't need. I'd imagine your app delegate is cluttered, and I'm curious as to how you're handling things like if the user decides to stop looking at a particular view before the XML related to that view has been sent back to your app and parsed.
If you're worried about having code duplication in your View Controllers, you can probably mitigate that by using Categories.
In the end though I think it's probably best for domain objects to handle this, and not the View Controllers. For example, in viewWillAppear you get or create an instance of a domain object and kick off a getData method which has the view controller as a delegate. All of the requesting/parsing is done in your domain object and when it's completed, it sends your view controller a getDataDidFinish message or something like that.
When I have a situation like this I tend to create an object that handles all the networking stuff for me. That way I end up being able to write code like:
[netObj getXML:somePlace];
The main reason I like this approach is because it keeps my code base tidy and minimizes duplicated code.
I have following problem:
I have built a tabbar application with 4 tabs. I want to pass a object/variable from the first tab controller to the third one and initialize this controller with the corresponding object.
I've already done some research. The best way, corresponding to a clean model approach, would be to call some initWithObject: method on the called viewcontroller.
How can I achieve this? How can I call the init method of the receivercontroller within the callercontroller? Can you give me some code example?
Edit:
To pass data between several views/classes etc simply create some Kind of data class which holds the data beeing shared between several classes. For more information follow the link:
Singleton
You need a data model object that stores the data for application.
A data model is a customized, standalone object accessible from anywhere in the application. The data model object knows nothing about any views or view controllers. It just stores data and the logical relationships between that data.
When different parts of the app need to write or read data, they write and read to the data model. In your case, view1 would save its data to the data model when it unloads and then view2 would read that data from the data model when it loads (or vice versa.)
In a properly designed app, no two view controllers should have access to the internal data of another controller. (The only reason a view controllers needs to know of the existence of another controller is if it has to trigger the loading of that other controller.)
The quick and dirty way to create a data model is to add attributes to the app delegate and then call the app delegate from the view controllers using:
YourAppDelegateClass *appDelegate = [[UIApplication sharedApplication] delegate];
myLocalProperty = appDelegate.someDataModelProperty;
This will work for small project but as your data grows complex, you should create a dedicated class for your data model.
Edit:
To clarify for your specific case, you would add the call to the data model when the receiver viewController becomes active.
Placing the data in an init method or a viewDidLoad won't work because in a UITabBar the users can switch back and forth without unloading the view or reinitializing the view controller.
The best place to retrieve changing data is in the viewWillAppear controller method. That way the data will be updated every time the user switches to that tab.
You might want to consider NSNotificationCenter (Reference); you register the one viewcontroller with the application notification center, and send a notification when a selection is made. When the notification is received, the other viewcontroller updates itself accordingly.
I don't think this is best practice (also check syntax) however I have got away with:
in the .h
otherclassref *otherclassname
#property (assign) otherclassname otherclassref;
and in the .m
#synthesize otherclassref;
then I just assign the reference from somewhere convenient e.g. the app delegate or wherever you are instantiating your viewcontrollers.
then the view controller can get a reference to the other view controller.
I add #class secondviewcontroller to the .h file for the firstviewcontroller and put put the #imports "secondviewcontroller.h" in the .m file of the first view controller. These are called forward references and prevent compiler errors resulting from having .h files referencing each other.
I am developing an iPhone app for some sweet undergrad research I've been working on. Sadly, my school doesn't offer software engineering / design classes so when it comes to questions of best practices in OO Design, I do a lot of reading.
My Dilemma:
My application loads a view (v1) where, upon user's button click, v1's controller class executes an action method. This action method should fill an array with objects. After that, the user will either execute the action again or click a different tab to load another view. Other views in the application will use the array that v1 populated.
So, where should this shared array be declared? Right now, it's in the AppDelegate class from when I was testing features without a GUI. Should I grab the AppDelegate singleton and add items to it in the v1ViewController? Should it be declared as static?
Thanks for the help!
^Buffalo
EDIT:
Follow-up Question: When interacting with a singleton, which is the better way to talk to it:
[[MyAwesomeSingleton sharedInstance] gimmeSomePizza];
or
MySingleton *s = [MySingleton sharedInstance];
[s gimmeSomePizza];
I guess what I'm wondering is, do you make the sharedInstance method call every time or do you define a pointer to the sharedInstance and then reference the pointer?
Using the app delegate to store data that's shared between views and view controllers is reasonable and appropriate.
In my apps, I view the app delegate as the controller part of MVC, with UIViews and view controllers all being part of the "view". I prefer to use a variant of MVC called Passive View that keeps the model and view parts of my app strictly segregated with only the controller connecting them.
I'm assuming that the array of objects you're storing is your app's model, so storing them on your app delegate makes sense. As Daniel D said, there's no need to make it static.
The app delegate is really the heart of your program. You create and initialize your model and views in your -applicationDidFinishLaunching: method and save your model data and view state in -applicationWillTerminate:. When your view controllers receive events that changes your model, you can call methods on your app delegate to make those changes.
You could store it in an ivar in the app delegate. You don't need to make it static since the app delegate is a singleton anyways (there's never more than 1 instance).
If the app delegate is getting a bit complicated, you can factor out the data storage into a separate model object or perhaps use Core Data.