Apple, for memory management issues, recommend defining outlets on properties, not in the attribute declaration. But, as far as I know, declaring properties exposes the class to external classes, so this could be dangerous.
On UIViewController we have the main view definition and the logic, so MVC is slightly cheated in this cases.
What is the beter approach, Apples's recommendation for memory-management or armored classes?
MVC isn't cheated by UIViewController, as that class implements a Controller. It defines connections between the View objects (usually stored in the XIB) and the Model objects (sometimes Core Data entities, sometimes other things).
Anyway. The point of defining outlets as properties is that you get to state explicitly what the memory management requirements on the properties are in the class interface. The NIB-loading mechanism uses the accessors if they exist, so you if you define a retain property, the outlet gets retained. If it can't find accessors it will set the instance variable directly.
Whether you define properties or not for your outlets is really a matter of personal taste. I do, because the outlets are set by an external object (the NSBundle class) so to my mind represent part of my view controller's API contract.
I believe you're thinking about this wrong.
Outlets only exist so that an external object, Interface Builder code and the nib decoders, can configure the instance of the class with the outlets. Hiding an outlet behind #protected or #private would defeat their entire purpose.
In good design this shouldn't be a problem because the view controllers should be relatively lightweight objects whose only function is to move data between the view and the model. The core logic of the app should be safely encapsulated in the model.
If you need a secure design, you can create the views programmatically and make them private but you lose all the flexibility and reuse that you get with outlets. It's a tradeoff.
In either case, however, this has nothing to do with memory management and properties. Whether a property is public, protected or private has nothing to do with how the properties memory is managed.
Related
I'm working on an app that has multiple view controllers for different screens and the whole app is about displaying data from an sqlite db.
My inicial design was to have a db object (the model), a main controller with exclusive access to this model and have all other view controllers merely manage visual aspects of windows,buttons,whathaveyou.
But I'm having a hard time realizing how to make the main controller be aware of all other view controllers throughout the app's life in the context of apple's ios app architecture.
I've thought of 3 approaches so far:
1 - NSNotificationCenter and have the main controller observe all other controllers?
2 - make the main controller delegate of all others? Though I'm still not clear on how to define a delegable (did I make this word up?) protocol in general. That is, even for objects that don't have a setDelegate method.
3 - passing an db object around to each view controller. Though this seems a bit like playing C passing state around..
Any thoughts?
Thanks!
Your approach should probably be one where the view controllers and models are as ignorant of each other as possible. This is a pretty common design pattern, I believe. You should have model objects that represent each logical "object" in your domain. Those objects may just be state. Next, you might want to create a controller (like you mentioned) that has access to your database and can make queries. The result of those queries should be used to construct instances of your logical model objects (e.g., XXPerson) and hand them off to whatever made the query. Given that, each view controller in your app should do the following:
Create its views and lay them out as appropriate
Instantiate your database controller object (and possibly hold on to it for further use)
Query the database for the data it needs via the database controller object
Use the resulting data (which should be returned as your logical model objects) to adjust the views or do whatever you need with them
Note that you could make use of a singleton for your database controller, but the singleton pattern is a loathsome one if you ask most good developers. :) Instead, there's really no reason why your application can't just create an instance of your database controller as needed, use it for some queries, then discard it afterwards.
Internally, of course, your database controller class should have singular, static access to the database and possibly synchronize access to write methods so that you don't run into issues with concurrency.
There are many possible design approaches, but one in which things are loosely coupled means that there isn't a bunch of interdependency going on, which is always a good thing. Let your model objects, database controller objects, and views all be independent of each other. The view controllers, of course, are the bridges that tie all those independent concepts together into a functional product.
That's my opinion, anyway. :)
It sounds like you're looking for a Data Access Object or service/store as part of your controller layer. I think that's a good idea and a common pattern in other languages that for some reason seems widely ignored in iOS apps.
Provide each of your view controllers with some object which manages access to your data store. You might want to only construct a single instance of that store but your controller's don't need to know that. As far as any individual controller is concerned it was given an object it can use to get and store model objects.
I don't think you should try to prevent your view controllers from accessing model objects at all. Rather introduce a service so that your view controllers don't need to know the details of how to load or persist those model objects. If necessary you can use that service to translate between one model and another if you find the need for a view-model or don't want your view controllers to work directly with whatever model objects you persist.
I think that a dependency like this should be a strong reference rather than a delegate and provided to each view controller when they are constructed via constructor-based or property-based dependency injection or some inversion of control container as appropriate for your app.
I'm trying to understand how to better implement the Model-View-Controller design pattern.
What object should 'own' the Model object? Should a single Controller instantiate (own) the Model object?
Here is an example scenario:
I have a UITabbarController containing two UIViewControllers (controllerA and controllerB). Obviously neither of these controllers own each other. I have a Model object which contains some data and also performs some network activity. Both controllerA and controllerB need to be able to make changes to the Model object. controllerB needs to know when changes have been made to the Model object (either by controllerA or returned results from the network activity). From recent reading:
I need KVO between the Model object and controllerB?
Should the Model object be a singleton? So that both controllers can modify it?
In simpler apps, I've had the viewController own the Model object. Is there any way for one controller to instantiate the Model object, but for other controllers to have write access to it?
I've also read about using the app delegate to own the Model object, and allowing controllers access via the app delegate share instance. This seems kind of ugly - using the app delegate singleton to globally access my Model object. Wouldn't it be better to just make my Model object a singleton?
I saw someone on SO give this link to iPhoneDevSDK, but the reasons for his method escape me. Again, isn't this getting the app delegate involved for something that should be just a singleton?
Mainly, is there any other way for two Controllers to access (write to) one Model, other than through the Model being a singleton?
Also, when a Controller owns another Controller (eg in a UINavigationController when the root view controller instantiates another view controller to stack on top of itself), would the best method for sharing the Model be for the root view controller to instantiate the Model, and pass it to the next view controller before pushing it onto the nav stack)?
Storing global objects in the AppDelegate gets really ugly as your project scales.
Ask yourself: What is the relationship between this model object(s) and other objects in my application? Is the relationship 1-to-1 or 1-to-n. If you need just one model to be accessed by various objects, then go for the singleton approach. If you need one object to have exactly one model, then keep a pointer to it in that object.
When faced with different, yet computationally correct, design alternatives a few areas to consider
Which approach minimizes lines of code?
Which approach causes the least amount of coupling and semantic coupling?
From the perspective of a programmer new to the project, which approach is easier to understand, maintain and harder to in-advertently introduce bugs.
If you start rolling global models into the AppDelegate, you'll eventually create a monolithic class which will be difficult to understand and harder to maintain. If you create a pointer to the model in each controller, you must pass a reference to that model each time a new control is instantiated, and it must pass down the pointer to any needing object which it instantiates. Essentially, you've created a cascading waterfall of passing the same pointer, bloated your interface file and constructor. Imagine if instead of 1 model you need to keep track of 5 model objects. Does it make sense for objects to have 5 pointers for 5 models which need to be passed-along to the constructor each and every time? This is how to make your projects buggy and unmaintainable.
In case it isn't obvious. The AppDelegate is just a singleton. When you roll all your models in your app delegate, you haven't avoided using singletons, you've just created a monolithic one.
Regarding KVO: This depends on what you're trying to accomplish. I'll give an example of where KVO is useful. Supposed you have a model object storing the application's user preferences.
#interface SettingsModel
.....
#property (nonatomic, retain) UIColor * backgroundColor;
#end
Other views in the application should update their background colour immediately whenever this settings changes. This can be solved easily using KVO:
[[SettingsModel getInstance] addObserver:self forKeyPath:#"backgroundColor" options:0 context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"backgroundColor"]){
self.view.backgroundColor = [[SettingsModel getInstance] backgroundColor];
}
}
The model can be referenced by multiple controllers. For a good insight on the basics of model-view-controller in iPhone development, scan through the first 2 lectures of the iPhone development course at Stanford (available for free in iTunesU, see info at Stanford at http://www.stanford.edu/class/cs193p/cgi-bin/drupal/ ) There seem to be more ways to get controllers informed about view and/or model updates.
I'm not sure why you're stuck on a Singleton, and I also don't see the problem in making a Singleton model object. I think it you also need to consider thread safety and memory leaks.
I'm new to Objective-C and the iPhone and thought I was getting the hang of it until, after many play apps, I ran into a really basic problem around MVCs, NIBs and IB. Are there any really clear explained examples of how to follow this framework that I could go back to?
#interface test1ViewController : UIViewController {
IBOutlet myView *myview;
IBOutlet myModel *mymodel;
}
Both the views and models are linked in by IBOutlets but instantiating the model object either kills the application or produces an object which does not respond to any messages.
I am also unclear as to where to carry best out initialisations. I currently do this over viewDidLoad in the view controller. Is there a standard way to do this and does the simulator actually always start up in the same way? Should one use awakeFromNib? Does it make any difference if I use plain code or the IB? And if I have use the IB, should it include a model object?
The MVC idea would make good sense for me here because I have potentially several views and view controllers all feeding back into - and sharing - one common central data model. Any references or advance on this newbie problem would be more than welcome!
I wouldn't spend too much time worrying about the 'classic' definition of MVC. iOS follows it, but there's a lot of confusing terminology. ("View Controller")
You say trying to use model kills your app. Are you retaining myModel? You have to retain all IBOutlets.
nibs are collections of "Freeze-Dried" objects. When you load a nib, the objects in it are "rehydrated", if you will. This means they spring back to life with all of their properties set to whatever they were when you froze them. So you talk of "instantiating" and "initializing" but this does not apply to IB. The objects are ALREADY instantiated and initialized. Imagine that compiling the nib 'pauses' the objects. When you load the nib, the objects resume doing whatever they were doing when frozen. They will get an awakeFromNib message, so that's a good place to put some code to check on what the state of the app is, see if you have to do stuff with your object to bring it up to speed.
viewDidLoad seems like an "initialization" method but don't be fooled. It's part of the view controller life cycle and it can be called more than once! (If your controller's view is purged as part of a low memory warning, viewDidLoad might be called again if the view has to be... wait for it... reloaded.) So, it's appropriate to put view setup stuff in viewDidLoad, but not other initialization type things.
For the "common data" thing, I like to create a singleton data model class. Your various views can set properties on the model, or send notifications. You can also use KVO (key value observing) to watch for changes in the model.
IB makes functionality invisible. I don't like it and I don't use IB any more, preferring to have everything in code. Then when you look at code you see what is going on - all the navigation controllers, all the formatters etc. - without switching over to IB. Maybe Xcode4 will make it better with integrated IB but I probably won't go back. Lots of people do like IB so try both methods and see what you like best.
IBOutlet/IBAction actually mean nothing to the compiler but they let IB recognise the ivars it can send messages to or that will write to elements in a xib. Your use of it here is a bit simplistic unless you really do have a model that only communicates one way with the xib. What you more usually have is a range of controls in the xib linked to the view object, the view communicating directly with the controller. The controller communicates with the model. Very loosely speaking, model is your internal representation of data and logic, view is what you see, controller is the glue between them.
The MVC line can be fuzzy and you just have to get comfortable with it. If you have a slider control with a value representing some value in your model then it can be hard to think of it as part of the interface especially when you persist the value and use it as a central part of your model. I like the Stanford iPhone class introduction of it. They don't spend a heap of time on it because it can be difficult to follow exactly and there are situations where it isn't best.
Notes from that class - you can find the video on iTunes to follow along.
Your use of viewDidLoad is correct, that's your chance to perform initialization on views and their objects. If using IB you will probably not have much to do there because you can set most properties in the xib. If not using IB you will use it a lot more.
A lot of times something like your model would be wired at runtime by your application delegate or by the view controller itself.
IB is generally used more to link views and controllers together, with the application handing around model(s).
That said, you should be able to have IB create an instance of your model and assign it in an IBOutlet. Was your model OK with just being created without the classic init method being called? Did it implement NSCoding properly?
I think I have a basic question that is sort of hard to look up, I think.
Objective-C for Iphone.
I want to create two view controller instances that message and update an instance of a Model Class. How do you do this? I would prefer no using singletons. It's basically an "I really want to learn from you guys because this is awesome and I want to be awesome too!" question.
I would prefer we keep app delegate, singletons, nsnotification center out of the picture. App delegate specifically in that I dont think I wnat to have my data object created by app delegate, but I may have to.
The way, as I understand it, this works is sort of like this. Navigation Controller creates instance of FirstLevelViewController. My FirstLevelViewController creates instances of my SecondLevelViewControllers and then when told to pushes them onto the navcontroller stack.
I have my Model Instance being created by my firstlevelviewcontroller instance. Is that wrong? I think I need a reference to the instance passed to my secondlevelviewcontroller, but I'm having trouble because I can't figure out what the instance name of the firstlevelviewcontroller is (I think NavController instantiated it).
Help is so very much appreciated.
Assuming the model stays the same object (it can be mutable but not deallocated within the lifetime of BOTH view controllers), one might use a separate variable in each view controller to point to the same model class, with each view controller not knowing about the other. This is of course dependent on your application specific logic -- if one view controller 'knows about' the other than of course it makes sense to have the model be 'owned' but the independent one, and accessible to the dependent one via properties. However this considered bad because it promotes code coupling and dependency, which is looked at as poor coding. As to how both view controllers get the same model instance, typically it would be set (preferably in initialization) by whatever knows about them both, such as a higher level view controller, or if they are root view controllers, the app delegate.
In AppKit we have "representedObject" available through NSViewController, this representedObject is generally set to ModelController or the model which the NSViewController displays, this works great with bindings as you just set the new representedObject and model details are updated in the view, BUT in case of iPhone (UIKit, with NO Cocoa bindings available), there is no such representedObject in UIViewController so here are few things I am interested in knowing:-
What is the best/recommended way of binding the model to the UIViewController?, preferably dont want to maintain lot of IBOutlets and calls setters to updated the changed model data for display in view.
How/When should the related model of the UIViewController be released?
When is the -[UIViewController dealloc] called, in the typical iPhone application.
Am looking for architecting some classes so that the UIViewController coordinates between the view and the model, but at the same time, deallocs the model when ever not necessary.
TIA.
That's the big problem with Cocoa bindings, it hides a lot of things that are very easy.
dealloc is called when the retain count reaches 0. For a view controller that will happen when other controllers have released it and it doesn't have any other retains. You shouldn't worry about this if you are doing memory management according to the rules.
Create a property for your model object, or model controller if you want to go to that level of abstraction. Using the property correctly (like always using self.model for receiving assignments), and release the object in your dealloc implementation, and set it to nil in viewWillUnload. Properties create the accessors for you.
As for releasing your model when not required, the above will handle that for you - there's no need to overthink it. If you are creating massive data structures, then you can consider building them in viewWillAppear and tearing down in viewWillDisappear in addition to the above.
You will need more outlets and glue code than you would with bindings; but you'll have to write a lot less code to manage your bindings. Remember that iPhone is supposed to be a less powerful device, and you are supposed to take greater care of resources - and the UIViewController api gives you the opportunities to do that.