Core Data is great to save arrays of objects “looking like” NSDictionaries. The Array Controller loads these objects, puts them into a table view, where we can edit them, add or remove objects (with default values). That’s great.
Now, imagine I want to store a single object.
My present solution is to use an NSArrayController with a single object as content. Of course it’s a strange solution, but it just need a single line of code: [theArrayController add: self]. I just have to verify if this object is not already present before creating it.
A better solution is to use an NSObjectController. But how do I know if the managed object already exists on disk? If I test if (!myEntity) the answer will always be FALSE because the entity has been created, but as a “class”. What about the instance? How can I test this? If I test for a key of an inexistent instance, I surely crash my app.
The single object is facultative. The user can create it or not. If he creates it, I want some defaults to be applied. If he uses it, I want to retrieve the stored values. He can also delete it, and re-create a fresh one.
Ideally, this job has to be done into a NSObjectController subclass.
Any link welcome.
Other sites didn’t respond as easily and quickly than here. Maybe I didn’t find the good one? The big trend is iOS development these days.
Somewhere early on you check to see if the ObjectController has any content.
For applying defaults, you can either set them in IB with the entity selected in the model editor, or you can assign your MO/Entity to a subclass (Model Editor / Configurations, then make sure it’s selected in the list of Entities and use menu Editor > Create NSModeledObject Subclass…) and generate a category on that subclass. In there you would use:
The main reason for using a category is so that your code won’t disappear if you re-save your MO/Entity as a subclass after any changes to the MO/Entity.
Looks like the way to set the controller to a fresh new default object is to:
That’s pretty similar to what I’ve done in my code. So there is no real difference between a NSObjectController and a single-record NSArrayController.
Conceptually, of course, it IS similar. I’ve tested with [[[myArrayController arrangedObject]count] == 0], which gave acceptable result, but is ugly. It made me feel a bit paranoid about the possible existence of a second or a third record.
NSObjectController’s content. Silly me. I am going to change for your solution.
May I ask you further questions about Core Data? This site is made primarily for ApplescriptObjC programmers, I know, but I could get answers only here.
Thank you very much for this clear and complete solution!
Well, I’m still kinda muddling my through, myself (LOTS of Google searches to figure out how-to), but I’m sure at some point somebody will be mixing ASOC and Cocoa (with some CD added) that might benefit from talk here. I happened to have just dealt with something similar to your issue as I came upon your post.
In my transition from ASOC to Obj-C I learned a lot from posts here that dealt with mixing ObjC/ASOC.
Should be… Now to figure out why it won’t add… Umm…
Although it should give you errors if not set, you have the Managed Object Context binding set to your MOC, right? How about the Content Object binding? That should be not used if you’re going to just run Add: on the controller. If you’re using the Content Object binding, then you need to take care of adding your new MapMO (or whatever it’s called) to the object it’s bound to. Although, I don’t know if canAdd would come back YES if you’re using it that way.
Another one to test (looking for possible clues or errors) would be to utilize, instead of Add, is to try - (id)newObject, which not only adds an object to the controller, but also returns the object (which should be the same as content: later on), and see if that remains nil.
If that still fails, make sure you can actually create one manually, using (again, if your object is called MapMO (the subclass of the Map entity)):
theMOC() comes from some convenience functions I wrote for myself (in the AppDelegate), which you might find handy:
if newMapMO is a valid MapMO, then see if you can use addObject:newMapMO to add it to the controller, I guess.
I think I see where the problem is: I am always in the same iteration. Now I understand why everything is fine when the
[[mapController content] setValue:[matrix colorReference] forKey:@“mapData”];
is sent a bit later by another object.
Rats. Curses. Darn. How to enforce the setValue to apply within the current loop?
If that works, then great. I usually make the subclasses so I can then add a category on it to run awakeFromInsert, awakeFromFetch, and prepareForDelete. Sometimes they don’t get used, but for others I have a creationDate and/or modifiedDate that I set on insert (self.creationDate = [NSDate date];), and some others that are maybe based on a GUI selection (if it’s not a direct relationship). Plus I tend to run an NSLog on these methods early in development so I can be sure things are flowing like I think they should (which isn’t always a match). For others I’ve set up observers on insert/fetch so I don’t have to remember to do that when I create a new MO.
Of that I have no idea. I’ve done little to no work with document based apps to start with, and have only set up and worked with the undo manager so far for only one sheet that edits an MO (just runs the undo on Cancel). I can see what you’re aiming for, but have no clue on what’s going wrong.