Design pattern for Core Data iPhone App - iphone

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.

Related

single controller managing a model and multiple viewcontrollers?

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.

How best to structure my code for a basic iPhone table/navigation database app?

Having worked through some tutorials on some basics via the iPhone, I'm struggling to determine how best to structure my code. The book I'm using points out things like "you wouldn't normally put this here, but for expediency...". Well, I'd like to know what one would "normally" do.
My application is somewhat simple - there is a table view showing a list of objects and one can add, remove, edit these objects (I plan to provide a more sophisticated organizational scheme later, but I'm keeping it simple to get something working).
So, I have a RootViewController that extends UITableViewController. When the "add" button is clicked I push a subclass of UIViewController onto the stack (this class is the "add/edit" form for my objects). I have a simple data structure-style class to hold the fields of the objects.
The apps like this in the book basically put an array inside the RootViewController and use a reference to the model class to represent the "object being edited". Basically, the models are all wrapped up in the view controllers. This seems wrong.
So, my question is: where do the models and the objects for managing them normally live?
And, does the answer to this depend on how I'm storing my objects? I have not done much with CoreData, though my plan was to use it for persistence of my objects. Will the hooks and boilerplate provided by XCode make this a nonissue?
Best answers will be pointers to some best practices type stuff, which I wasn't able to easily find via Google or on Apple's Dev site.
First of all you are right about your intuition that it seems wrong. As you described the model is stored in the view controllers. That is a bad idea. By doing so you are violating the model-view-controller paradigm, which makes your code hard to maintain.
So what you need to do now is get your model in a separate object or tree of objects or even better use CoreData, which is also great in terms of memory management.
As you want to use CoreData you should have a look at the UIFetchedResultsController class which you will use to obtain the objects from the managedObjectContext which will be your model.
What you would do in your table view - detail edit example is:
Fetch the contents of the table view using a fetch request and setting it on the NSFetchedResultsController you hold as an instance variable in the rootViewController
Set this rootViewController as the delegate of that NSFetchedResultsController
If an item is checked or the add button is pressed push your detail view controller on the stack, pass the object to be edited with it, or nil if it is a new object. Also pass the managedObjectContext to the detailViewController. Update or create the object.
Implement the delegate methods of NSFetchedResultsController in your rootViewController and there you reload the contents of the table when necessary.
What you gain is a nice and clear separation of model (CoreData's managedObjectContext) the controller (rootViewController and detailViewController) and you views. If you now edit an entry by using the detail view, your rootViewController is notified via your NSFetchedResultsController and automatically updated. What you also gain is that you do not have a strong reference among the viewControllers in your application.
Btw, you set up your CoreData stuff in the application's delegate. There is a lot of boilerplate code around in Xcode and on the ADC. Check out the Recipies app [1] in which this approach I just descriped is used. There are also some videos about CoreData on Apple's developers site.
[1]: http://developer.apple.com/iphone/library/samplecode/iPhoneCoreDataRecipes/Introduction/Intro.html CoreDataRecipies

Where to place the "Core Data Stack" in a Cocoa/Cocoa Touch application

In the iPhone Core Data Template, Apple places the Core Data Stack in the App Delegate.
My initial inclination however is to move this code into it's own class whose responsibility is to handle the management of the Core Data Stack.
Do you typically encapsulate this functionality within its own class or do you leave it in the App Delegate?
Summary: There is no need to create a singleton to manage the Core Data stack; indeed doing so is likely to be counter-productive.
The Core Data stack happens to be created by the application delegate. Importantly, however, as all the examples show, the stack (principally the managed object context) is not retrieved directly from the stack(*). Instead the context is passed to the first view controller, and from them on a context or a managed object is passed from one view controller to the next (as described in Accessing the Core Data Stack). This follows the basic pattern for iPhone all applications: you pass data or a model controller from one view controller to the next.
The typical role of the singleton as described here is as a model controller. With Core Data, the managed object context is already a model controller. It also gives you the ability to access other parts of the stack if needs be. Moreover, in some situations (as described in the documentation) you might want to use a different context to perform a discrete set of actions. The appropriate unit of currency for a view controller is therefore usually a managed object context, otherwise a managed object. Using and passing a singleton object that manages a stack (and from which you retrieve a context) typically at best introduces a needless level of indirection, and at worst introduces unnecessary application rigidity.
(*) No example retrieves the context using:
[[UIApplication delegate] managedObjectContext];
I have a singleton class that i let do my core data managment and i do not leave it on the app delegate. I rather not clutter the app delegate class with methods i might need for conviniece such as fetching certain objects etc
I leave the core data logic in the App delegate for the following reasons:
1) I do not see any real advantage in moving this code in other classes: the concept of delegation is perfectly fulfilled by the core data logic being handled by the App delegate since the core data model is actually a fundamental part of your application;
2) In all of the sample code I have seen, including Apple samples, the core data stuff is handled by the App delegate;
3) Even in Core Data books it is common practice to have the App delegate handle core data related code;
4) Personally I do not think that readability or anything else is actually improved by having ad hoc classes for core data, but this is a matter of personal taste and I will not argue here what approach is the best one. To me, simplicity while retaining functionality is important.
The question I'd ask myself, in your case, is "who does the Core Data stack 'belong' to?" The data itself is really province of the application, isn't it? (C.F. Core Data on the Mac, where you might have an application capable of working with multiple documents at a time, so the Core Data stack belongs to each document.)
In any Cocoa/Cocoa Touch application, the App Delegate is usually the preferred means of customizing the behavior of the application, so this is the natural place for the Core Data stack.
Now, the problem I suspect you're having is that it feels wrong to constantly write things like:
NSManagedObjectContext *context = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
What I typically do in these cases is write functions (not methods) like this:
NSManagedObjectContext *UIAppManagedObjectContext() {
return [*(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
I write a similar function for the NSPersistentStoreCoordinator and the NSManagedObjectModel. I put all of these in the App Delegate's .h/.m files, since these are application-level objects, too.
I'll just list this in a new answer. (I've scrapped my previous FJSCoreDataStack class in favor of this)
My new way of handling this has been to use a category on NSManagedObjectContext. Ive added the following class methods:
+ (NSManagedObjectContext *)defaultManagedObjectContext;
+ (NSManagedObjectContext *)scratchpadManagedObjectContext;
+ (NSManagedObjectModel *)managedObjectModel;
+ (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
+ (NSString *)applicationDocumentsDirectory;
This keeps everything out of my app delegate, and gives singleton access should I choose to use it. However, I still use dependency injection from the App Delegate (as mmalc has said, it introduces inflexibility into my code). I have simply moved all of the "Core Data Stack" code into the NSManagedObjectCOntext Category.
I like passing the reference around, especially since I have a nice "scratchpad context" method. This keeps my View Controllers flexible since I have not committed them to the "defaultManagedObjectContext".
Also relevant to the conversation in the iPhone world (and may have a bearing on your architecture):
NSFetchedResultsController and constructing NSFetchRequests
I'm in favour of having the app delegate know where the model starts, and having the model know where the Managed Object Context is. The Core Data-"ness" of the model seems like an implementation detail of the model to me, the controller classes (like the app delegate) should just ask "give me this information about the model" and the model should know how to answer that question. Therefore having a Core Data object available through a controller object seems like a leaky abstraction.

Can I make NSManagedObject into a singleton?

I have a NSManagedObject object filled with data I want to use in multiple view controllers.
Can I make this object into a singleton and use it in multiple view controllers? Or should I use a different approach?
As an alternative to a singleton, consider making it a property in your application delegate, initialized when the application finishes launching.
In your view controller, set a NSManagedObject reference to this property's value when the view is instantiated.
You are already passing around the NSManagedObjectContext. You can use that to fetch the data you want at any time.
I don't know how Core Data would react to you making a singleton instance of it. For one, NSmanagedObject doesn't use the same methods for initialization that NSObject does.
It uses -awakeFromInsert and -awakeFromFetch. So you already have a problem.
See this article from Marcus Zarra (Core Data Guru).
In short, just perform a new fetch to get the data you need, no need to work a singleton in there.
That depends on why you would want to make it a singleton, if you have trouble passing it to all the entities that need to access the data, using a singleton is not a good solution anyway. It usually introduces more problems rather than solving any.
If you are worried about multiple edits to the same object, Core Data has mechanisms to handle that, see the "Change Management" chapter in the "Core Data Programming Guide"

Application Design and AppDelegate

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.