I'm particularly interested in how to follow Apple's standards with respect to a good MVC pattern design. Let me illustrate my question with an example.
Lets say I have a number of fairly complicated UI elements on screen such as UITableView. Basically these elements require a datasource and a delegate to handle interaction.
There are two approaches to working with this.
I can have the same subclass of UITableViewController handling all of the elements and dynamically handling things based on the requesting UITableView.
Second approach would be to have "lightweight" controllers that would manage each individual view. In iOS 4.x you're not allowed to have multiple UIViewControllers, so these controllers would be more for managing state and interaction.
I don't like the first approach because it doesn't scale and seems to combine things. What if I have multiple complex objects of dissimilar type?
The second approach seems better. Objects are encapsulated better - separation of concerns. The only downside seems to be increased complexity of communication. Lightweight controllers would have to either delegate back to the real view controllers or they'd have to have a handle to something to perform real actions.
What is your experience with either of these approaches? Is there a better solution for decomposing a complicated interface?
Thanks
You can always re-assign the delegate and datasource of a UITableView to something else. It does not have to be a UITableViewController. As long as it fulfills 1 of the protocol methods for the delegate and datasource.
So you may have a UIViewController (controller) that is powered by a nib/xib (view created by Interface Builder). In that interface you've added a tableview and set it's delegate and datasource to the file owner (back to the controller).
Then the UIViewController may communicate to Core Data (model) to retrieve related objects in response to the UITableView delegate messages.
Or, the UIViewController can re-assign the delegate/data-source to a lightweight provider that fulfills the protocols to make it more encapsulated.
This is the style of MVC Apple is suggesting.
Related
I want to follow MVC for my current project, in which 7-8 UIViewController subclasses will be there.
There are more than 30 classes (NSObjectsubclasses) for maintaining data and server connections.
Most of the time server connection manager class will send local notifications to UIViewController subclassess to make view transitions. I want to make it happen in centralized manner. Meaning from a single class.
What I want to do is, Implement a single class which handles all my UIViewController Transitions.
Any idea on how I can implement this ???
Note: I don't know the pros and cons of following this kind of approach. Even I don't know this is feasible or not.
I think I know what you mean. My best bet, would be a singleton, that would receive two UIViewControllers references and then would apply the animations between the two. This way you would have a centralized place where you could your animations. Probably a more complete solution, would be receiving the two UIViewControllers and two blocks, one for the animation block and another one for the completion block.
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'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...).
Im building an app that will use a Core Data model. I pretty new at Objective C and my usual design patterns does not really apply on Core Data and Objective C, at least I can't seem to find examples that confirms they will.
I have been through the Apple Developer examples and different sources on the intertubes.
It seems that to leverage Core Data I need to pass the managedObjectContext to each of my viewControllers, have the viewController implement the NSFetchedResultsControllerDelegate and then implement each of the methods for doing a fetch and subsequently implement
NSFetchedResultsChangeInsert
NSFetchedResultsChangeDelete
NSFetchedResultsChangeMove
NSFetchedResultsChangeUpdate
This adds approximately 100+ lines of code in each viewController and it is 90% the same code I write again and again. Plus I have to pass everything around and keep track of it's memory footprint.
In other languages I would build a singleton model of a few classes that held methods for maintaining and delivering data upon request, available from anywhere. It seems I can't take that approach in Objective C. If I where to build a static Class that took a managedObjectContext and returned me what I needed, I would still have to pass the managedObjectContext around to every view and it wouldn't be asynchronously like when I implement delegate methods that just gets called when a result is ready.
I hope this makes sense and that someone can either confirm that there is no other reasonable way to do it or help point me in a direction for wrapping this up in a good way.
Thanks:)
Core Data is not nearly as complicated as you describe.
Generally, an iPhone app has a "main" managed object context, which is generally owned by the app delegate. So long as you can get the app delegate (hint: [[UIApplication sharedApplication] delegate]) you have access to the managed object context. I like to define a static global variable to hold a reference to my app delegate to make life easier.
There's generally a one-to-one correspondence between NSFetchedResultsController instances and UITableView instances. Aside from populating table views, it's exceedingly rare that you would need an NSFetchedResultsController. If you have a number of similar views (e.g. a tab bar that lets you view the same data in different ways a la the iPod app), it would behoove you to create a single base class that configures the NSFetchedResultsController and derive your specific view controllers from that.
Now, when you create view controllers to edit an object, it's generally a good idea to do that in a separate managed object context. If the user cancels, you just discard the context and the changes go away. Again, you don't really need an NSFetchedResultsController for this because these views are only concerned with a single object.
When you're done editing, you save: the managed object context. The objects that manage your other managed object contexts should implement the NSFetchedResultsControllerDelegate methods to keep the table view in sync. Again, this can be implemented in a base class so you can generalize this functionality for related view controllers.
Do you absolutely have to use a CoreData model, or would something using a NSCoder (NSArchiver, NSKeyedArchiver, etc) work? I've found that CoreData is overkill for most applications.
Also, could you clarify why you can't take an approach using singletons? I've used singleton factories in a number of applications without issues. It's fairly easy to define class-level methods that operate on a shared (singleton) instance.
I'm new to development on the iPhone. Just about every sample project (as well as the default project templates) have one or more delegates and controllers. Can someone give me a breakdown of what the delegates are responsible for vs. what the controllers are supposed to do?
The simplest way I can think to differentiate the two are:
A delegate is a protocol (interface) that defines methods that an object implements in order to receive specific messages from other objects. Delegates objects are most often used to receive asynchronous callbacks such as user input, I/O.
A controller is an object that usually contains UI elements (views, controls, etc.) and data, and both receives and send messages to the various objects within it. In many cases, a controller is a delegate and can implement several delegate protocols to receive events from multiple objects.
Keep in mind that many UI elements and controls let you pass events back to the controller by linking them to an IBAction method in Interface Builder. This is very handy as it doesn't require extra code to implement delegates. However, some other APIs such as the ABPeoplePickerNavigationController or NSURLConnection have no visualization in Interface Builder and so must use delegates to handle their events.
A delegate is some object that implements a set of methods which either your application or the framework you link against depends on for functioning. It is a means of implementing a delegation based design pattern wherein the responsibility for performing an action is transferred from some root source to an interested third party. For instance, UIApplication has delegate methods that provide a third party with the ability to perform operations at certain times during the applications lifetime. It can be though of as a milestone in a timeline into which you can contribute to the story.
A controller is a totally different animal and is responsible for doing, well, the controlling. A ViewController is charged with managing views - for loading them into memory from disk when they are needed and unloading them when they are not. They transform content from some underlying model object into a form that is usable by your view objects, load content into your in-memory model from the disk or from the internet, and dump the contents back to disk when you save and/or quit.