views:

56

answers:

2

Is it possible to create a custom controller key for an NSArrayController? There are keys for "arrangedObjects", "selection" etc... Is it possible to implement your own? I can't seem to find any info on this anywhere.

My reason for wanting to do this (besides it seeming like a useful thing to be able to do) is:

I have Entity "Car", with Attributes "color" and "mileage", and an array controller, "CarArrayController" which holds these objects and displays them in a table. Below the table I want two text fields one displaying total red car mileage and the other total blue car mileage. Obviously I can display the total of all the cars: Bind Value To "[email protected]", but so far I have been unable to get separate sums for red and blue cars without implementing more arrays or array controllers.

If I could create a Controller Key "arrangedRedCarObjects" which obviously only returned the red cars, I could have a binding to: "[email protected]".

I can't seem to find any way to achieve my goal :(

There must be a way to get the result I need (it seems like a generic problem), please help!

Cheers,

Oli

A: 

If you have some way to ask a car whether it is red or blue, you can create two secondary array controllers fed by the primary (bind secondary controller's content array to the primary controller's arrangedObjects) each with a filter predicate that restricts the array to the proper color of car.

Peter Hosey
I've already tried that and it works. But I want a way to solve the problem without having to create a new array (controller) for each color of car. There must be a way to add custom Controller Keys?! Surely???
Charlie
+1  A: 

The controller keys are more than just strings: They are methods of NSArrayController, each of which goes through some logic, creates an object, and returns that object. You can't just add keys because there wouldn't be any logic behind the key.

So, if you don't want to make more array controllers, you need to make a more capable array controller. Make a subclass of NSArrayController that implements methods for the keys you want, and in those methods, ask yourself for the source array (e.g., arrangedObjects), perform whatever restriction and rearrangement you want, and return that result.

Don't forget to declare your new methods as dependent on their source properties (e.g., arrangedRedCarObjects as dependent on arrangedObjects). That's another thing that just adding keys to a list wouldn't be able to accomplish: It wouldn't know what source property/-ies your new key should depend on.

Peter Hosey
That goes a long way towards enlightening me about my problem, thank you! I can subclass NSArrayController to provide additional methods which return filtered parts of the array (I can also do this using Catagories to add methods to the NSArrayController class). How though, do i then bind to those methods? ie can I somehow link the textbox to "[email protected]" ??
Charlie
Charlie: Yup. As I said, the controller keys are methods. If you add a method and make it observable (e.g., by making it dependent on an existing key), you have added a key, and you bind to it the same way as one of the stock keys. (Don't include it in the Model Key Path.)
Peter Hosey
ah ok, so maybe I am not making my new methods observable. I have been trying to bind to them the same way as using stock keys, ie "arrangeBlueCarObjects" as opposed to "arrangeObjects" but the application then wouldn't run. I'll try and make them observable (how?) and get back to you. Thanks for you help
Charlie
Charlie: I told you how in both the answer and my comment. What do you mean “the application then wouldn't run”?
Peter Hosey
I have a subclass of NSArrayController with a method which provides blue cars only. I don't think it is currently observable though. When I hit "Build and Go" I get the error: "[<NSCFArray 0x1918e0> addObserver:forKeyPath:options:context:] is not supported. Key path: @sum.mileage". How do I go about making my method dependent on an existing key (eg arrangedObjects (I presume that is what you mean?))?
Charlie
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/KeyValueObserving/ answers that, but that won't help with that exception. You can't observe a property of an array, since it has no way to express which objects the property changed for; you have to observe through the controller. If what you have works when you change `arrangedBlueCarObjects` to `arrangedObjects`, then I'm not sure how to overcome that.
Peter Hosey
Any chance you could provide some example code, I'm really struggling to get this to work. I can code a method to return a filtered array: "return [[self arrangedObjects] filteredArrayUsingPredicate:bluePredicate];" But i can't figure out how to bind to the method or result, along with any other methods that need to be implemented for KVO etc.
Charlie
You would bind to this new property using Interface Builder—as I said, you should be able to switch between `arrangedBlueCarObjects` and `arrangedObjects` for the controller key and have it work either way. Try the latter and make sure that works. You shouldn't need to implement anything else except the dependency.
Peter Hosey
Ok, I've read through that documentation on KVO and added some code to ensure the object registers for KVO but I'm still having difficulties - it doesn't work and I can't see why not and I actually don't even know if what i want to do is possible as I haven't seen an example of it anywhere. Anyhow, you can see my attempt here: http://stackoverflow.com/questions/3728308/is-it-possible-to-bind-to-a-property-of-an-nsarraycontroller and tell me where I'm going wrong!
Charlie