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.
Related
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.
I have a theoretical-practical question. I can't understand how I must do. I have a class let's call them DataManager that manage all plist writing-reading things and I need to get access to plist (i.e. work with that DataManager class) from different UIViewControllers.
I also have one class, I call it ModelManager, that is work with all kind of "utilities classes", include my DataManager. ModelManager works only with one complex UIViewController right now, let's call it MainUIViewController for clearness. And for now, I thought that all calls from UIViewControllers will be comes to ModelManager and from it to end-call classes. But now I'm confused.
Here is an illustration of my architecture:
I'm see different approaches and don't know how to decide and if there is some rules or guides for that. So, here is my choices:
1) I add some interface to ModelManager and from my another UIViewController (not a MainUIViewController) allocate and initialise it.
2) I add some interface to ModelManager and create a property with reference to ModelManager in another UIViewController and when segues performs set this property from MainUIViewController.
3) Work with DataManager itself and allocate and initialise it from another UIViewController
4) Work with DataManager itself and create a property with reference to DataManager in another UIViewController and when segues performs set this property from MainUIViewController.
Which approach is correct?
I know that this is some kind of depends from developer which approach to choose, but I never read and didn't find any tutorial or guide of how to develop multi-class architecture.
Ask me about any circumstance that you want to know.
You can use a singleton or you can instantiate one instance of the class in your app delegate and pass it around to all your view controllers via #propertys on each controller. There's no right answer, it's mostly a matter of preference. I prefer to make my ModelManager/DataManager type classes singletons, but a lot of people are rabidly opposed to singletons. However, if you work with Cocoa for any length of time you'll find that it's full of them (NSUserDefaults, NSFileManager, UIDevice, probably some others I'm forgetting).
Here's a good example on how to create singletons: http://www.galloway.me.uk/tutorials/singleton-classes/
BTW: Once you have your singleton, learn how to use KVO to make your view controllers respond to changes in the model. It's pretty fantastic once you get the hang of it. http://nshipster.com/key-value-observing/
I got a app that uses navigation controller and tableViews and I want to create a class to do some simple storage of information that stays persistent while navigating through the different views without saving to disk.
I can either create an singleton with only class methods, but in this case I´d need to create
the collection class holding the data as an instance variable (as #properties don´t work with class methods). I only ever see objects declared in properties in iOS, so is this frowned upon?
The class would look something like this
header:
+ (BOOL) addObject: (id) object;
+ (BOOL) removeObject: (id) object;
+ (NSInteger) count;
and privately I´ll have an NSArray for storage
NSArray *cache;
But is this a good way of achieving the task? or would it be possible to have a non-singelton class with instance methods and use that same instance of the class in the different table views? if so, how would I do that?
First, ALL readwrite properties auto-synthesize instance variables (unless you implement BOTH setter AND getter).
Second, if that information is global to the entire (or most of the) App, a singleton is just what you need. You don't need to keep it as a property (or an ivar). It's a singleton, it keeps its own pointer.
If you still want to go with a property, you will have to pass it some how to every VC in your App (prepareForSegue:sender: probably if you're using storyboards).
First figure out what global information you need. Then figure out what objects you already have that have a lifetime consistent with that global information, and which are logically associated with the info. Eg, if you need an array of info to "back up" a UITableView, store the pointer to that array in the table view data source instance.
It is rarely necessary to create a "singleton", and having lots of singletons is usually a sign of poor programming.
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.
I'd like a critique of the following method I use to create objects:
In the interface file:
MyClass * _anObject;
...
#property (retain, nonatomic) MyClass * anObject;
In the implementation file:
#property anObject = _anObject
so far, so simple. Now let's override the default getter:
(MyClass *) anObject {
if(_anObject == nil) {
self.anObject = [[MyClass alloc] init];
[_anObject dowWhateverInitAction];
}
return _anObject;
}
EDIT:
My original question was about creating the object only (instead of the whole life-cycle), but I'm adding the following so that it doesn't through off anyone:
- (void) dealloc {
self.anObject = nil;
}
/EDIT
The main point of the exercise is that setter is used inside the getter. I've used it for all kind of objects (ViewController, myriad other types, etc.) The advantage I get is:
An object is created only when needed. It makes the app pretty fast
(for example, there are 6-7 views in an app, only one gets created in
the beginning).
I don't have to worry about creating an object before it's used... it happens automatically.
I don't have to worry about where the object will be needed the first time... I can just access the object as if it were already there and if it were not, it just gets created fresh.
Questions:
Does it happen to be an established pattern?
Do you see any drawbacks of doing this?
This pattern is quite commonly used as a lazy-loading technique, whereby the object is only created when first requested.
There could be a drawback to this approach if the object being created lazily takes a fair amount of computation to create, and is requested in a time-critical situation (in which case, it doesn't make sense to use this technique). However I would say that this is a reasonable enough thing to do should the object be quick to create.
The only thing wrong with your implementation (assuming you’re not using ARC yet) is that you’ve got a memory leak—using the setter means that your MyClass instance is getting over-retained. You should either release or autorelease _anObject after that initialization, or assign its value directly instead of calling the setter.
Aside from that, this is totally fine, and it’s a good pattern to follow when the MyClass is an object that isn’t necessarily needed right away and can be recreated easily: your response to memory warnings can include a self.anObject = nil to free up the instance’s memory.
It looks like a decent lazy initialization. Philosophically, one can argue that the drawback is that a getter has a side effect. But the side effect is not visible outside and it is kind of an established pattern.
Lazy instantiation is an established pattern, and it is used by Apple in their (terrible) Core Data templates.
The main drawback is that it is overly complex and often unnecessary. I've lost count of the number of times I've seen this where it would make more sense to simply instantiate the objects when the parent object is initialised.
If a simple solution is just as good, go with the simpler solution. Is there are particular reason why you can't instantiate these objects when the parent object is initialised? Perhaps the child objects take up a lot of memory and are only rarely accessed? Does it take a significant amount of time to create the object and you are initialising your parent object in a time-sensitive section of your application? Then feel free to use lazy instantiation. But for the most part, you should prefer the simpler approach.
It's also not thread-safe.
Regarding your advantages:
An object is created only when needed. It makes the app pretty fast (for example, there are 6-7 views in an app, only one gets created in the beginning).
Are you referring to views or view controllers? Your statement doesn't really make sense with views. I don't normally find myself needing to store view controllers in instance variables/properties at all, I instantiate them when I need to switch to them and push them onto the navigation stack, then pop them off when I'm done.
Have you tried your app without using this pattern? Conjecture about performance is often wrong.
I don't have to worry about creating an object before it's used... it happens automatically.
No, now you have to worry about writing a special getter instead. This is more complex and prone to mistakes than simple instantiation. It also makes your application logic and performance more difficult to understand and reason about.
I don't have to worry about where the object will be needed the first time... I can just access the object as if it were already there and if it were not, it just gets created fresh.
You don't have to worry about that when you instantiate it during your parent object's initialisation.
Yes this is an established pattern. I often use lazy instantiation like this as an alternative to cluttering up -init or -viewDidLoad with a bunch of setup code. I would assign the value to the instance variable instead of using the synthesized setter in the event that this object ends up being created as a result of something happening in -init.