Core data design patterns - ios

For my first IOS app I plan to incorporate CoreData however I'm a little unsure about the correct design pattern I should use.
In my app delegate I have the following 3 properties.
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
I feel the best way to use these objects are to inject them into the constructor of all the relevant view controllers that need to access data from inside CoreData.
The cleanest way I can think of for that would be to create some kind of Repository class for each table I have in my data model which will house the above 3 objects and provide helper methods for accessing the tables data e.g. fetchAllTeams(). These repository classes can then be injected into the relevant view controllers instead of injecting all 3 objects above.
Does this sound like the correct thing to be doing in the world of CoreData & Objective-c?
Also whats the best way to create these repository classes, should I remove the default core data code and properties from the appDelegate (generated automatically) and place them inside an abstract repository class.
Should each instance of a repository have its own version of NSPersistentStoreCoordinator, NSManagedObjectModel and NSManagedObjectContext or should a single instance of these objects be shared among all repository instances passed in by the appDelegate.

Firstly, the base code that a Core-Data sets you up with can make the whole thing very confusing. The thing to understand is that Core-Data is a kind of wrapper around a variety of database technologies (sqlite, binary, xml) and by doing this, relieves you of the need to directly touch the database. The main class you are going to worry about in the beginning is NSManagedObjectContext. Think of it as a snapshot of the underling database which you can modify as you please and when you are done write that NSManagedObjectContext onto the database. The other classes you have there are really only needed for more fine-grained, low level control, and since this is your first app, best to leave those alone. You should read this, it is large, but you will gain a lot of understanding from it, especially how everything connects and their role.
To summarise though:
Really you only need to pass around the NSManagedObjectContext
You can do this my making an instance variable in every View Controller, OR,
You shouldn't go making more than one per app, unless you really need to, and then you need to make sure you merge them back together
You don't really need to create a repository of all the objects because NSManagedObjectContext does this for you...kinda... it will load objects into memory conditionally, there is a lot to this but the place to start is learning what a fault is (all in Apples documentation under NSManagedObjectContext or NSManagedObject)
think about what your objects represent and do. You can subclass NSManagedObject to represent your Core-Data object and place logic and validation inside of it - super handy.
Look into classes like NSFetchRequest and NSPredicate which are the two core classes for getting objects out of the NSManagedObjectContext.
Look into classes like NSFetchedResultsController which can tie very nicely into UI objects like UITableView.
Finally, Core-Data is a beast, and often you find yourself repeating common tasks all the time. You should look into this excellent framework which adds all sorts of helpers (like an easily accessible instance of NSManagedObjectContext, and one line object fetching, creating, deleting).

With regards this bit, my two cents...
Also whats the best way to create these repository classes, should I remove the default core data code and properties from the appDelegate (generated automatically) and place them inside an abstract repository class.
I'd definitely take out all the code that Xcode generates from the app delegate and put its in its own class. This might be a good read in explaining the basic core data stuff: http://commandshift.co.uk/blog/2013/09/07/the-core-data-stack/ (via #jrturton).
Should each instance of a repository have its own version of NSPersistentStoreCoordinator, NSManagedObjectModel and NSManagedObjectContext or should a single instance of these objects be shared among all repository instances passed in by the appDelegate.
You typically only have one persistent store coordinator (another good post here on that).
You add models to the coordinator, and also persistent stores. You can have multiple managed object contexts on a coordinator if you like.
A good example is a master detail style structure, you have a table view controller (backed by a fetch results controller), this uses the shared instance of the managed object context. When selected a managed object in the table, you pass this object into your detail view controller when creating it. You don't need to pass through, or use the shared context as that managed object will have its own managedObjectContext.
You can even create further child contexts from this if you like - think of this as a temporary context, you can change any objects registered in this context, and if you change your mind and don't want the changes any more you can just ignore and not save the child context.
Unless you have no way of accessing a managed object, or are at the top of the stack you can use the shared context. Keeping the use of shared context to only when its needed, I personally think keeps things simpler as you don't have to worry about what's (and where) using the global shared context through out your app. (Granted the shared context will be the base one anyway, but using a managed objects own context will mean when you save any changes to that context you know that that object will be effected).
Also to deal with simpler accessing and creating of managed objects I recommend mogenerator, there's a good post here about setting it up.

Related

Upcasting NSObject to RLMObject

How would you upcast an NSObject to a RLMObject?
Say you have a model object that's of type NSObject, and say you wanted to dynamically upcast it to RLMObject, how would you do it?
It's worth mentioning that RLMObject's properties can't be populated at runtime, else I probably would've done it through <objc/runtime.h>. (I mean.. They technically can... It would just be too much of a hack)
What I'm trying to do:
The main purpose behind this is to create a caching framework that would dynamically choose between interchangeable caching dependencies such as Realm, SQLite, Core Data, etc. For example, I imagine having a preprocessor flag to hopefully switch from using Realm to SQLite, without having to change my models subclass.
This would require all of my models being a subclass of NSObject, simply because RLMObject wouldn't make sense in a SQLite environment for example.
I've been thinking about this a whole lot, and here's my approach:
1) Loop through the NSObject's properties at runtime & create a key/value object of them
2) Create a subclass of RLMObject at runtime and copy the property list from the passed NSObject model
3) Utilize Realm's initWithValue: to populate the properties
What's your opinion?
It looks like this method that you mention - RLMObject.initWithValue or a static equivalent createInDefaultRealmWithValue has to be called on an RLMObject subclass, or else it throws an exception: "Object type 'RLMObject' is not managed by the Realm".
You need a dynamic schema creation API (what underlies RLMObject), that I don't see being a public API.
An alternative would be to manually encode the object to some dictionary or NSData and attach it to a fixed RLMObject subclass.
You might lose some Realm features by not inheriting RLMObject like knowing when the object becomes dirty, but still probably get some success.
I think you'll get the same problem with Core Data. Normally Core Data supports only NSManagedObject subclasses, and moreover it requires you to define a fixed schema in advance in a model file (represented in code by NSManagedObjectModel).
Of course you could just treat your objects as dictionaries of property names and values, and place them into a giant ("type","id","property","value") table, but it is not the best approach (likely to be slow).
The same strategy is possible to implement with the SQLite backend. Interesting to see which schema would you choose for this.
I'd recommend to look at key-value stores as the backend for this, and avoid SQL. Or treat SQL as a key-value store, as in ("type+id", "encoded_object_data") :)

Making a single copy of a singleton

a design question:
I have a singleton (in objective-C but it doesn't really matter)
The singleton is a class (object) that is actually a data structure that many classes access, and is single (hence - a singleton)
Now I want to add the ability to undo - which is actually saving a snapshot of the state of the object - so I can go back to it.
What I actually need to do is to break the singleton-ness of the object (need one copy of it).
But this will not allow me to share it conveniently between all the classes.
Ideas?
"The singleton is a class (object) that is actually a data structure that many classes access, and is single"
I think it is easier to make your singleton object have a collection of the data structure. Then you just create copies of the data structure instead of copies of singleton.
The singleton pattern came in vogue about 10 years ago when design patterns were first being adopted by developers. In the years since then, the singleton has fallen into disuse because it is notoriously difficult to mock in unit tests. So the simplest answer is to abandon the singleton pattern completely in favor of a more friendly pattern.
You could implement a - (id) copy method in your singleton class.
In this method, allocate a new instance of your class, and set all it's properties to a copy of your shared instance's properties.

Have multiple instances of a class point to one object #property

I will try to make this question as understandable as possible. I am implementing core data in my app, and I need to access the NSManagedObjectContext from around 10,000 different instances of a class (this class extends UIView). The Core Data stores what is displayed on these instances and the class builds it.
Everything that I have found so far uses View Controllers, of which you only have one instance, so you can just alloc init the VC in AppDelegate, set an #property for NSManagedObjectContext and be on your way. This does not work for my program.
What I want to do is have many instances of my CoreDataHelper class (which I will alloc init in the class that I have around 10,000 instances of, which all have a property pointing to the same NSManagedObjectContext. Is this a possible way to do it or will I have to make my program less flexible by moving all of the code to create the 10,000 different objects to the View Controller?
Sure, just put your NSManagedObjectContext in a singleton and all your instances can access the single class.
It does not matter if you get your managed object context from a singleton or from your app delegate (where presumably you the core data stack is set up by default).
To follow the pattern suggested by Apple with view controllers, do the exact same thing with your views: give them a #property of type NSManagedObjectContext and set it during initialization. Seems straight forward enough.
The advantage of the singleton is that you do not even need the property on your view but can call the singleton instead. But why go there? From your comments I understand that you do not really know how a singleton works. You don't need it. Go with the class property solution.
One more caveat: with your setup, you are seriously braking the MVC architecture by giving the views access to your data. Instead, you should indeed have a view controller do this and then populate your views with the retrieved data. I do not think that there is a compelling reason to deviate from this principle.

Is a property reference to an NSManagedObject unsafe?

In the book Learning Core Data for iOS, the author creates several UIViewControllers which each have a property that refers to an NSManagedObjectID.
In example,
#interface LocationAtShopViewController : UIViewController
#property (strong, nonatomic) NSManagedObjectID *selectedObjectID;
// ... other properties and methods
#end
In this manner, he is able to pass an NSManagedObjectID from one controller to another and retrieve the associated NSManagedObject object using NSManagedObjectContext's existingObjectWithID:error: method.
Further, he doesn't ever set an NSManagedObject object directly (even if he already has a variable reference to it), nor does he keep a reference to the NSManagedObject object very long (instead, he retrieves it in each method that he needs it).
Is it unsafe (i.e. will cause crashes or lead to unexpected behavior in certain circumstances) to pass an NSManagedObject directly between controllers via a property reference, or simply keep a reference to it on a controller?
In example,
#interface LocationAtShopViewController : UIViewController
#property (strong, nonatomic) LocationAtShop *locationAtShop;
// ... other properties and methods
#end
Assuming a single, shared NSManagedObjectContext is used, so disregard issues caused by passing between multiple contexts, which isn't safe in general.
There is no reason to avoid using the managed object directly, provided that:
You only use the managed object with a single managed object context, and
You either
only ever use the managed object on a single thread or queue, or
Make sure to use performBlock or performBlockAndWait when working on a different queue.
Keeping only the object ID may be less error-prone since it makes it a lot harder to accidentally mix up contexts or queues. That may make it a better idea for less experienced developers, who are therefore less likely to screw things up. But it's certainly not wrong nor even especially dangerous to keep the object itself.
Is it safe ?
Yes, it's safe, with some caveats:
Per Tom Harrington's answer, in general it's safe to store an NSManagedObject as a property on a controller.
However, there are situations in which this can cause problems. Notably,
If the referenced NSManagedObject is deleted and its context is saved, the property must explicitly be set to nil.
If you do not explicitly set the property to nil, the next time you try to access an attribute on the object, it will cause a CoreData could not fulfill a fault crash.
Why did the author of Learning Core Data for iOS pass and store the NSManagedObjectID instead of the NSManagedObject?
The likely reasons may include:
If instead of storing the NSManagedObject as a property you stored the NSManagedObjectID, you don't have to worry too much about the object being deleted.
This is because NSManagedObjectContext's method existingObjectWithID:error: will return nil in the event that the object cannot be fetched, or does not exist, or cannot be faulted.
So, it's safer to store the NSManagedObjectID as a property than it is to store the NSManagedObject, if deletion of the object is possible.

Recipes to pass NSManagedObjects amongs UIViewControllers

Within an application it's possible to have different UIViewControllers that need to share the same NSManagedObject. I'm usually do the following:
#interface CustomController : UIViewController
#property (nonatomic, retain) ProductNSManagedObject* productManaged;
#end
Then when I istantiate CustomController I inject it like the following:
customController.productManaged = ....
once done, CustomController is responsible to release it.
This approach works well (I don't know if is it correct), but what to do when a controller need that object but it's not a direct child of the controller that has that object? e.g.
MainController -> ChildController -> SubChildController -> ....
where MainController has the managed object.
Do I have to create a lot of intermediary properties or do I need to execute a fresh NSFetchRequest or something else?
The same aspect could be applied to the NSManagedObjectContext. Searching around I've found that the context can be grabbed from the application delegate that posseses it (if any). But this approach lacks of flexibility as Marcus Zarra wrote in passing-around-a-nsmanagedobjectcontext-on-the-iphone.
Any suggestions? Thank you in advance.
I create a singleton object that contains the managed object context that will be used throughout the application. I put any supporting code related to the data (e.g., persistent store coordinator) inside this singleton and keep all of the view and controller information separated from it.
In one case, I need a managed object context for another thread. It became apparent that it would be useful to refactor and put that context inside the same singleton. Then merging between the two contexts can be done inside the singleton.
This has helped me manage my code. You might consider it.
This is a very common question (see here and here for related ones). As I wrote in the answers for the related questions, you should stay away from singletons and create a separate object that will take care of object instantiation, of creating the object graph for your application. This separate object can hold references to all shared objects and supply them to the objects being built, so that none of your regular objects has to keep a reference to something just to pass it as a dependency to other objects. See this blog post for more rationale against singleton misuse and for further pointers, especially the articles by Miško Hevery.
I have created a sample Xcode project that shows how to wire an app without singletons, keeping the coupling low and resolving other singleton issues. It’s very simple at the moment, I will add more common use cases later.

Resources