How expensive is it to retrieve a model object from an nsarraycontroller? - objective-c

I've a window with a table. The table lists several model objects by name. Those model objects back a window and that window's components all depend on the model objects for their values.
Some tables on that window cannot be bound to the model object and must be populated using a data source. In this situation I retrieve the currently selected object from the array controller (selected because the user clicked on the table that lists the model objects) and manipulate them manually.
My question is: how expensive is it to retrieve the model object from the array each time I need it? Should I create a global variable of the type model object and set it every time the user clicks on that table or is it ok to retrieve a value from the array controller every time I need it?

Since all objects in Cocoa are passed around using pointers, there will be very little overhead involved in retrieving your model object from an NSArrayController. Even if you were to use bindings, the same sort of accesses are going on behind the scenes.

Premature optimization is the root of all evil. Do things the clear way first. Once you have your app working, profile it using Shark or Instruments to find where it really is slow.

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.

General CoreData Performance

i have a more or less general question about using coredata the most efficient way.
i have attempted two different approaches of managing data that is shown in a view of my project.
Approach 1: when the view gets loaded i perform all coredata fetches and store the results in an array, the view then retrieves the displayed objects from the array. (ie: objectAtIndex:...)
Approach 2: the viewcontroller itself lets my data handling class perform fetches on the go, whenever a specific coredata object is needed it gets fetched.
on my current project this involes about 200-500 objects that need to be sorted and displayed in a tableview according to their attributes.
the fetch methods are the same wether i load all objects first or when i load them in batches (of correct attributes).
the difference is mainly in the cellForRow method where i have to decide if i want to pick the objects out of an array or directly from coredata.
both methods work just fine, i dont really see any performance differences just now, but i fear that with scaling of the project & more data one or the other way might be slower.
what do you think is the better way to do this?
With larger data sets there may be an advantage in terms of peak memory footprint to using NSFetchedResultsController controller that is, presumably optimized to fetch just the right amount of data from the persistent store based on the table size.
With NSFetchedResultsController you have control over the fetch batch size which you can tune for performance based on the size and number of the managed objects being fetched, etc.

Core Data: force one attribute to load before others

I have some transient attributes in my Entity that are derived from one other transient attribute (call is X). When I do a fetch, it seems to try to load all attributes in no particular order, so if X is taking some time to calculate, the other derived attributes try to use X and it's null so it causes issues.
Is there any way to force Core Data to ensure loading one attribute before other attributes can read from it? Or force the other attributes to reload once attribute X has done loading? Any other technique anyone would recommend? I'm using this in an iOS tableView backed by an NSFetchedResultsController.
No you can't force attributes to "load" in order because attributes don't load. You are initializing objects here and not reading cells in a procedural database.
I'm going to guess that your trying to calculate some value based on the attributes or counts of external objects. If so, then you can get serious slow downs while the other objects are faulted in so that their values can be accessed.
If so, then you've got a data model design problem. I've never seen a transient value so complex that its calculation impaired operation. You probably need to break it apart or even move it to its own object.
E.g Suppose you've got a data model that simulates a group of people with Person objects. You want some behavior of each Person object to change depending on how many people their are. So, when there are less than five each person does "X" if there are 6 to 10 you do "Y" and so on.
In that circumstance, it would be best to create a second entity related to all the Person objects that tracks the number of Person objects total. Then getting the count of all Person objects or the collective sum of one of the Person entity attributes becomes fast and trivial.

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.