Core Data - Managed object question - objective-c

I have 2 basic questions regarding Core Data;
What exactly is a managed object -- Is it equivalent to 1 instance of a class. For example, if there is an entity called Shape which has attributes like no of sides & color and if there are 5 entries displayed in a table, does it mean there are 5 managed objects each with attributes no. of sides & color. I am a bit confused about this basic concept.
What exactly is the relationship between Fetched Results Controller (FRC) and a table view? I know the delegate methods, but how exactly is the table view impacted/related to FRC ?
Any basic examples will be really useful. Thank you.

Q1. A managed object is a representation of some entity that has been persisted by an application. It is simply a generic abstraction away from the actual persisted type. So you are right in saying that the managed object will have the same keys/properties as the concrete type. As the NSManagedbject class implements the key-value coding pattern you can query its key/values at runtime...
- (id)valueForKey:(NSString *)key
For full documentation on NSManagedObject see here
Q2. The fetched results controller is what your UIViewController is to your UIView. It contains the logic that controls persistence for your table view. Its sole purpose in life is to keep database handling logic out of your UITableView. It does so by allowing you to define the behaviour you want to execute in the context of your UITableView. What I mean by this is that its delegate provides methods with signatures that explicitly imply an effect on a UITableView.

Q1. Yes, there are 5 managed objects out there and available to you. You could put all five in an array if you wanted to. Managed Object is simply a term that means you have code to manage the Insert, Change, and Delete actions into the database - in otherwords, some code manages it through its life cycle. You get at it through an FRC, the FRC ^fetches^ instances of the object from the database, and allows your code to ^control^ what happens to the ^result^. Hence the name.

Related

How to pass the model to a Controller in Core Data

Say I have a Core Data class called RecipeBook which has a property (relationship) called recipes, a NSSet of Recipe Objects.
I display the RecipeBooks on a UITableView and when the user taps on a cell, it should display the Recipes on another UITableViewController.
What should I pass as the model to this last UITableViewController:
a context and a fetchRequest
or the NSSet of Recipe objects?
If there's a change to the db will the NSSet "automagically" update?
From your description I'd probably pass the selected RecipeBook instance. From that I can (presumably) get all the recipes contained in the book and display them in the table. That assumes that a relationship exists from RecipeBook to Recipe which-- based on your description-- should be true. If I need to do any other work with the data store, I could ask the RecipeBook for its managed object context and work with that.
No NSSet of fetched objects is going to update automatically. But the relationship from a RecipeBook to its Recipes will update any time a recipe is added or removed from the recipe book.
And finally-- passing any of this directly to a UITableView doesn't make a lot of sense. Apple's iOS frameworks are designed with MVC in mind, and going against that will make things a lot harder than they need to be. If you have a UITableViewController, you could pass your model objects to that.
Generally, you shouldn't pass "model" objects to view objects.
My favorite way to think about it is that views are actually another form of a model (think of them both as simply representations of data). The controller's job is to ensure that neither representation needs to know anything about how the other stores it's representation.
So basically, your controller will be your data delegate, and is responsible for properly populating table cells with it's own references to your core data models.
The automagically question depends on your core data setup, but usually the answer is yes.
By default, CD uses key-value coding, which simply lets you access properties with valueForKey:. More advanced setups involve having Xcode generate classes for you, in which case a few mouse clicks get you "dot notation" accessor methods regenerated from an updated model.

Inserting controller logic between model and view when using Interface Builder, NSObjectController sub-classes, and bindings

I've been struggling to understand the best way to insert controller logic when using IB, NSObjectController sub-classes and bindings.
I need to insert controller logic between the model and the view, and I'm struggling to find an elegant way to do so. Yes, you can send actions to the file owner and handle controller logic in there, but when some core data models can extend across fifty entities or more with deep relationship structures, this starts to mount up to an incredible amount of boiler-plate code.
A very simplified example would be this; imagine you have an entity with four string attributes myTextWinter, myTextSpring, myTextSummer, myTextAutumn. You have a view which connects to this in IB via an NSObjectController. Now, say the user can select which 'Season' they wish to view by choosing Spring, Summer, Autumn, Winter from a Menu somewhere - when that season is selected, I would like to display the appropriate season's text.
In this simplified example I could probably fetch the object in the NSDocument sub-class, create a property called mySeasonText which I bind to in my view, and then check my NSUserDefaults for the appropriate season and route the requests to the appropriate attribute in the model.
The problem comes when I have fifty entities, some with relationships some two, three or more deep, each with their own set of season specific text attributes that I wish to switch between when selecting from the Season menu. Or if I have a bunch of nsarraycontrollers chained together to access objects at a deeper, and deeper level.
To date, I've been doing the following; adding a property in each of my model objects called 'mySeasonText', then grabbing the setting from my controller setting, and routing to the appropriate season. I refresh these objects whenever a new item in the menu is selected.
Whilst this works and eliminates an absolute ton of boiler-plate code, my controller logic is now in my model.
There must be a better way! Could someone please point me in the correct direction?
This is a tricky topic. Apple even mentions these challenges in its own documentation:
By using the bindings technology, you can easily create a Cocoa MVC application whose views directly observe model objects to receive notifications of state changes. However, there is a theoretical problem with this design. View objects and model objects should be the most reusable objects in an application. […] Design-wise, it's best to keep model and view objects separate from each other, because that enhances their reusability.
The design pattern you are looking for is a Mediating Controller - a way to use the cocoa-bindings classes to insert controller logic:
Mediating controllers are typically ready-made objects that you drag from the Interface Builder library. You can configure [Mediating controllers] to establish the bindings between properties of view objects and properties of the controller object, and then between those controller properties and specific properties of a model object. As a result, when users change a value displayed in a view object, the new value is automatically communicated to a model object for storage—via the mediating controller; and when a property of a model changes its value, that change is communicated to a view for display.
Here is how I like to think of them: Have you ever seen a movie or TV show where two characters need to talk, but they don't speak any of the same languages? They find someone else (or in a comedy 5 other people) who each have one language in common, and they communicate by playing a giant game of translation telephone.
Mediating controllers are kind of like that.
As your application grows they learn all the super specific rules about where to look for this one thing on this one view. This is the kind of code that an app needs to run, but you rightly feel that it is nasty when put in your model.
For several specific and detailed examples, Apple provides this amazingly detailed document: Bindings Message Flow.
For some really good discussions about this and related MVC + Bindings please see:
MVC and cocoa bindings best practices question
Why use NSObjectController?
Replacing model objects using an NSArrayController

Objective-C undo manager questions

I'm reading a book on Objective-c and learning about the undo manager. The concept seems very simple but the provided example seems overly complex. Basically, I have a table view connected to an NSArrayController and I add or remove people to an array and I can edit their names and stuff. Because the example uses NSArrayController and bindings, add and remove are automatic and all of the editing is automatic.
To use the undo manager, from what I understand, I need to implement my own methods to add/remove/edit.
These methods I've implemented to do the adding and removing and get called automatically due to key value coding:
- (void)removeObjectFromEmployeesAtIndex:(int)index;
- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index;
Then for editing, I had to register the class as an observer and observe changes to edit:
- (void)changeKeyPath:(NSString *)keyPath
ofObject:(id)obj
toValue:(id)newValue
Here are my questions:
Why do I have to do so much? My understanding was that using the NSArrayController and bindings was supposed to make things like adding/removing/editing items easier and more automatic. But if I have to implement all of these methods manually anyway just to add undo support, why use NSArrayController or bindings at all?
What's going on behind the scenes? In Interface Builder, the add button is connected to the add method on the NSArrayController. How then does my insertObject method get called? I know it's through key value coding but what makes the NSArrayController's add method get overridden just b/c my document implements this method?
The solution is asymmetric. I use one concept to handle undoing add/remove and another concept to handle undoing edits. Couldn't I also just observe changes to the array? I suppose it would complicate the observeValueForKeyPath method, but would that make more sense?
1) Nearly, but not quite. If you think of your application code being divided into three overall areas: Model, View and Controller (as documented here) then the Cocoa/XCode environment provides you with a 'code-free' way of handling the basics of each: IB for the view, Core Data for the model, and Bindings / Object Controllers for the controller.
Undo management is primarily a concern of the model, not the view or controller. So it's not really Bindings or the Object controller's job to manage this stuff. It looks like your problem is that you're using arrays as your data objects, which are too lightweight to handle this stuff. If you want undo support, you'll want to use core data to handle the model and give you this stuff for free, or hand-roll your own model objects, (which will probably contain arrays) which handle this logic.
FWIW, once you've done this, bindings will indirectly make your life much easier, as when an undo command reverts your data to its previous state, the view will automatically reflect the changes.
Also, NSArrayController's name is slightly misleading -- it isn't there to 'control arrays'. It's really for controlling data objects which have to-many relationships to other data objects. Which brings me on to...
2) KVC allows you to treat a to-many relationship between an object and other objects as an array or set, regardless of how the relationship is actually implemented. It does so by requiring you to implement methods fitting a naming convention, which very closely match the primitive methods of arrays and sets. KVC-compliant objects will return a proxy array or set when you call mutableArrayValueForKey: or mutableSetValueForKey:, which exposes those methods as an array. Roughly, that's how NSArrayController knows what to call --- KVC maps between the primitive objects of an array and some methods whose manes it generates from the key. Since you don't want to use arrays as your data objects, it's generally very useful to be able to treat any to-many relationship as if it were just an ordinary collection.
3) I think this is related to you handling undo in the wrong place. Implement KVC-compliant methods to get/set properties in your data objects, have them update the undoManger at the same time as setting the data. You'll need a special method for the undomanager to revert changes, as you don't want undos to be recorded as undoable. Or you could just use Core Data and get all this stuff for free...

Elegantly add object to arraycontroller, which itself is linked to another arraycontroller?

I'm new to OS X programming but generally liking it. I have the following problem:
I have two core data entities linked through a one-to-many with their respective arraycontrollers (Stock Controller and Price History Controller, where the latter controller is bound to the Stock Controller, with Controller Key = selection and Model Key Path = priceHistory, which is the relationship that links the stock entity to the PriceDataPoint entity, controlled by the Price History Controller.
This all works like magic in my UI, where I can select stocks and add/remove price points to each one when it is selected. However, I need to be able to do this programmatically as well.
If I simply call [stockController add:self] the UI updates with new objects with the correct default values, linked to the selected stock -- even though 'self' is not the correct class/entity. This is one point of confusion for me, which I don't understand (I understand that the Stock Controller knows about the selected stock through the KVO binding and would likely set the relationship as required, but I don't get how it 'casts' 'self', which is a fairly random class into the object type required (a plain NSManagedObject)? Secondly, if I do this, how do I get a reference back to that object so I can edit its values?
More importantly, however, if I then follow the Apple examples, create a new NSManagedObject through NSEntityDescription:insertNewObjectForEntity: and use [stockController addObject:Newly created Object] I can write the values I want before adding it but the relationship to the 'parent' stock is not set by the addObjects: method. I am sure I can figure out how to write this, too but with everything else in Cocoa being so elegant this just feels odd so I am hoping that someone here can clear this up very quickly and point me to an elegant way of doing it.
First, let's dispel the magic by stating Core Data is built to work with the Cocoa Bindings mechanism (which gives you array controllers, among other things) and is built atop Key Value Coding / Key Value Observing mechanisms. The Core Data documentation clearly states you should have a good background in these technologies to understand how / why things are working.
For your first issue, you said you're confused by the -add: method of NSArrayController. Have you looked at the signature/prototype? The argument (where you pass self) is (id)sender, which is the hallmark of a basic action (see "target/action" in the docs). You can pass self, some other object, or even nil if you want. The argument is NOT the object you wish to add to the collection managed by the array controller.
For your second issue, you're on the right track if you want to customize things or keep a reference to the newly-inserted object. You can use the -addObject: method (which does take the object to add as its argument) but you'll have to tell the array controller to -fetch: (another action w/sender as argument) in order to refresh the controller AND anything bound to its contents (such as a table/outline).

Pattern for Ownership and References Between Multiple Controllers and Semi-Shared Objects?

For example, I have window (non-document model) - it has a controller associated with it. Within this window, I have a list and an add button. Clicking the add button brings up another "detail" window / dialog (with an associated controller) that allows the user to enter the detail information, click ok, and then have the item propagated back to the original window's list. Obviously, I would have an underlying model object that holds a collection of these entities (let's call the singular entity an Entity for reference).
Conceivably, I have just one main window, so I would likely have only one collection of entities. I could stash it in the main window's controller – but then how do I pass it to the detail window? I mean, I probably don't want to be passing this collection around - difficult to read / maintain / multithread. I could pass a reference to the parent controller and use it to access the collection, but that seems to smell as well. I could stash it in the appDelegate and then access it as a "global" variable via [[NSApplication sharedApplication] delegate] - that seems a little excessive, considering an app delegate doesn't really have anything to do with the model. Another global variable style could be an option - I could make the Entity class have a singleton factory for the collection and class methods to access the collection. This seems like a bigger abuse than the appDelegate - especially considering the Entity object and the collection of said entities are two separate concerns. I could create an EntityCollection class that has a singleton factory method and then object methods for interaction with the collection (or split into a true factory class and collection class for a little bit more OO goodness and easy replacement for test objects). If I was using the NSDocument model, I guess I could stash it there, but that's not much different than stashing it in the application delegate (although the NSDocument itself does seemingly represent the model in some fashion).
I've spent quite a bit of time lately on the server side, so I haven't had to deal with the client-side much, and when I have, I just brute forced a solution. In the end, there are a billion ways to skin this cat, and it just seems like none of them are terribly clean or pretty. What is the generally accepted Cocoa programmer's way of doing this? Or, better yet, what is the optimum way to do this?
I think your conceptual problem is that you're thinking of the interface as the core of the application and the data model as something you have to find a place to cram somewhere.
This is backwards. The data model is the core of the program and everything else is grafted onto the data model. The model should encapsulate all the logical operations that can be performed on the data. An interface, GUI or otherwise, merely sends messages to the data model requesting certain actions.
Starting with this concept, it's easy to see that having the data model universally accessible is not sloppy design. Since the model contains all the logic for altering the data, you can have an arbitrarily large number of interfaces accessing it without the data becoming muddled or code complicated because the model changes the data only according to its own internal rules.
The best way to accomplish universal access is to create a singleton producing class and then put the header for the class in the application prefix headers. That way, any object in the app can access the data model.
Edit01:
Let me clarify the important difference between a naked global variable and a globally accessible class encapsulated data model.
Historically, we viewed global variables as bad design because they were just raw variables. Any part of the code could alter them at will. This nakedness led to obvious problems has you had to continuously guard against some stray fragment of code altering the global and then bringing the app down.
However, in a class based global, the global variable is encapsulated and protected by the logic implemented by the encapsulating class. This encapsulation means that while any stray fragment of code may attempt to alter the global variable inside the class, it can only do so if the encapsulating class permits the alteration. The automatic validation reduces the complexity of the code because all the validation logic resides in one single class instead of being spread out all over the app in any random place that data might be manipulated.
Instead of creating a weak point as in the case of a naked global variable, you create strong and universal validation and management of the data. If you find a problem with the data management, you only have to fix it in one place. Once you have a properly configured data model, the rest of the app becomes ridiculously easy to write.
My initial reaction would be to use a "modal delegate," a lot like NSAlerts do. You'd create your detail window by passing a reference to a delegate, which the detail window would message when it is done creating the object. The delegate—which would probably be the controller for the main window—could then handle the "done editing" message and add the object to the collection. I'd tend to not want to pass the collection around directly.
I support the EntityCollection class. If you have a list of objects, that list should be managed outside a specific controller, in my opinion.
I use the singleton method where the class itself manages it's own collections, setup and teardown. I find this separates the database/storage functionality from the controllers and keeps things clean. It's nice and easy to just call [Object objects] and have it return a reference to my list of objects.