NSTableColumn binding using Collection Operators like #sum - cocoa

Mac OS X. CoreData app. NSTableView controlled by NSArrayController bound to managed object context for the Country entity. The Country entity has a 'name' attribute and a to-many relationship, 'branches', to a Branch entity. The Branch entity has a 'sales' attribute (an NSNumber).
The NSTableView has two NSTableColumns. The first shows the name of the Country. The second should show the total sales for that Country across all its Branches.
The first column's value is bound to the NSArrayController's arrangedObjects with a model key path of 'name'. No problem there.
The second column's value is bound to the NSArrayController's arrangedObjects with a model key path of 'branches.#sum.sales'. This doesn't work. I get the error message: " addObserver:forKeyPath:options:context:] is not supported. Key path: #sum.sales"
If, instead, I add a 'totalSales' method to my Country class and the method is implemented as follows:
- (NSNumber *)totalSales
{
return [[self branches] valueForKeyPath:#"#sum.sales"];
}
and I then bind the column to 'totalSales' it works fine. My understanding of the Collection Operators documentation is that this should be the same as simply binding to 'branches.#sum.sales'. I can't see why the latter doesn't work. Any ideas? I have seen similar questions in this and other forums, but have yet to see an explanation or solution.

I don't know if this is still topic for you, but it surely does need an answer.
The second column's value should be bound to NSArrayController in exactly the sam way as first. I don't know why you made it differently and what actually you wanted to achieve.
Your first task was to bind table columns to array columns and this works the same way for all the columns and types.
Second task is to get sum of certain NSTableColumn bound to certain other object, like NSTextfield. And this is done like this:
[totalCountField bind: #"value" toObject: arrayController
withKeyPath:#"arrangedObjects.#sum.price" options:nil];

Related

Binding an Ordered Relationship with an NSArrayController

How does one bind an NSArrayController's content to the entities in an ordered to-many relationship?
I have an unordered to-many relationship in my Core Data model, and an NSArrayController whose Content Set is bound to that relationship from the parent entity. This works fine, the data is accessible from the NSArrayController, no problem.
I decided during development that it would be better to allow users to manually reorder these child objects, so I changed the relationship to an ordered one. Now, when my NSArrayController is being created from my nib, the following error is presented:
Cannot create NSSet from object Relationship '...' fault on managed object ... of class _NSFaultingMutableOrderedSet
Now actually, I think this all makes sense: It's an ordered relationship, so now I'm getting an ordered set. Binding it to Content Array also would be inappropriate, since it's now an NSOrderedSet, not an array. My question is: Now how do I bind this relationship's data back into the NSArrayController?
I came across this discussion while searching to see if there've been any new developments on this front. In a shipping app I currently bind the array controller's content array to orderedSetKey.#array and it works just fine, not sure if I discovered that myself or if someone else suggested it somewhere.
The fundamental problem is that a Core Data ordered to-many relationship returns an NSOrderedSet, and NSOrderedSet is not a subclass of NSSet. Any array controller bindings that expect an NSSet will fail.
Tom Fewster has a detailed blog post describing the use of NSValueTransformer to work around this shortcoming, converting between NSOrderedSet and NSArray on the fly. He also provides a sample implementation on Github.

Data is not displayed in the table

I have created a small application,in which i have draged and droped a NSTableView onto the window and binded to an datasource, in the datasource i have created NSMutableArray and added 2 records to it. And also defined methods numberOfRowsInTableView and rest of the methods.
When i run the application it is showing the rows but the data is not displaying.
So. You've connected your table view's datasource outlet to some controller object that adopts NSTableDataSource protocol.
You mention numberOfRowsInTableView, which tells the table how many rows it should expect but lump together the "rest of the methods." One of those other methods is exactly responsible for showing the data for a given row and column.
What seems to be happening is this:
Table: "How many rows we got here?"
Data Source: "Three."
Table: "Gimme the object to display at
row 0, column 0."
Data Source: [ sound of crickets
chirping ]
You should probably post the exact code you're using for your implementation of the tableView:objectValueForTableColumn:row: method. Remember to include the method signature itself, given its importance in being recognized as the selector the protocol is looking for.

Showing serial nos. in a table column using NSArrayController and cocoa bindings

I have a simple question:
How to show serial nos. or (row no. +
1) in a table column using cocoa bindings and array controller?
I have made an application using cocoa bindings and array controller, in which I am displaying names of certain persons in a table column. The class from which I am displaying is named as: Person. Now I want to show serial nos. in first column, such that list gets displayed like this :
1 / John
2 / Peter
It is very easy to do if I use data source method:
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
I just need to return something like this :
return [NSString stringWithFormat:#"%d",rowIndex+1];
but I am not getting how to do this via cocoa binding and array controller.
Can anyone suggest me solution for it?
Thanks,
Miraaj
One way you can do this is to actually mix using bindings and a data source with the same table view. Go ahead and hook up bindings for the rest of your table columns, but leave the one you want to display the indices in unbound. Then, just implement the table data source as normal for just that one column. It should only ever ask you for data fir Amy unbound columns, and just use the bound data for the rest.

Getting a unique identifier for each element of NSArrayController's content

I'm making a custom view that I want to be bindings/core data compatible and represent a collection of data (a la NSTableView)
Is there any way my view can refer to a specific subset of the elements in the collection (other than the current selection) after a change by the user?
A bit of context:
The view is going to display a number of user-moveable boxes in a 2D space. Each box corresponds to a record in the model. Several can be moved at once, and I can't rely on the delta value being the same for each box (so no adding a delta to each selected object).
I guess I'm looking for something like an id assigned to each element of the content array by NSArrayController, so that the view can associate that id with each box. My first thought was to use the the index in a content array, but this could be messed up by undo/redo. I could subclass NSArrayController and get it to auto-generate an id for each model item, but does cocoa already do something like this already? Feels like I might be missing something.
I should have mentioned that I originally tried keeping each of the content array's elements stored in the view (as Peter suggests), but had them stored as keys in an dictionary.
The objects in the view didn't match the keys in the dictionary, so I assumed this meant that NSArrayController changed the proxy objects it uses to stand for model objects.
However, it turned out that NSDictionary copies its keys, so it seems to be no good for situations where you want to associate a particular instance of an object with another.
NSMapTable is its more flexible cousin, and can be configured not to copy its keys.
Why not just refer to the objects themselves? You can keep them in a set or array, whichever is appropriate.
If you really need an identifier of some sort: What for? What are you going to do with it?

What does "Controller Key" mean in Interface Builder > Inspector > Bindings?

I can't find in the Docs where they explain all those fields and what they mean. Especially "Controller Key" is not clear to me.
[Copying my answer on another question…]
The controller key is the key for the (property of the controller object) you're binding to. The model key path is the key path by which the bound object can ask the model objects for more basic objects, such as strings or images, or for other model objects (i.e., drill down into the model).
An example: Let's say you have a Person objects in an array controller, and each Person has a name. You bind a table column to the array controller, controller key arrangedObjects (thereby getting the model objects), model key path name (thereby getting the value objects).
A more complex example: Suppose you have an array controller of Departments. Each Department contains Persons (employees in the department). You can bind your People array controller to the Departments controller, controller key arrangedObjects (getting the Department model objects), model key path #distinctUnionOfObjects.employees (getting the Person model objects), and then bind a table column to the People controller, controller key arrangedObjects, model key path name.
That table would be for people who work for your company; if you have a separate table of prospective employees, you can create Person objects for them, too, and they won't show up in the table of existing employees because they're not in a Department. When you hire them, you'll add them to one or more Departments; then, they'll show up in the People array controller automatically, because that array controller is observing the employees of all of the Departments.
The Controller Key pop-up menu is a way to help you discover what keys the controller (typically a NSArrayController, NSObjectController or a NSTreeController) presents.
The best example is the selection key of NSArrayControllers, which contains the set of selected objects. What is confusing is the NSObjectController presents a 'selection' key too, although the controller can control only a single object (therefore the selection = the object).
I agree that it is not clear at all. I personnally began to understand it when I bound my objects programmatically (i.e. using the bind:toObject:withKeyPath:options: method).
It has to do with key-value coding. You can bind a control in IB to a value in your controller. To connect that value, you have to specify the keypath to it. For example, if you have a textfield in IB and you want to bind it to say a field called 'name' in your controller, you would specify 'name' as the keypath. You then need to set up your name field in your controller to be accessible through key-value coding. This is done in 10.5 by using the #property and #synthesize specifiers.
Take a look at this topic: Cocoa Key Value Bindings: What are the explanations of the various options for Controller Key?
I posted an explanation of where to find definitions for all Controller Key's there.

Resources