May 13, 2008
Earlier this week I was working on a project where I wanted to filter a table view based on tags. The data model I was working with was very simple. My table view was bound to an array of objects through an NSArrayController, and each object had it’s own array of NSStrings which represented tags. My goal was to create a filter bar control, which I could bind to the array controller in order to popular the list of tags. The filter bar would display each unique tag once, and update itself when objects were added or removed, or an object’s tag array changed.
At first this seemed somewhat complicated. Implementing key value observing is easy, but I would have to observe both the array of objects and also each object’s individual tag array. Handling insertions, removals, and replacements adds to the complexity of the code I needed to write, all in order to solve what should be a simple problem. When I stopped to think about it, I went back to the documentation and found there was a much, much easier way of dealing with this situation:
[filterBar bind:@"tags" toObject:arrayController withKeyPath:@"arrangedObjects.@distinctUnionOfArrays.tags" options:nil];
One last thing; in my case I actually had to use two array controllers, one for the filter bar, and another for the table view. Since I was using the filter bar to create an NSPredicate for the table view’s array controller, if I bound both UI objects to that same array controller I would be removing tags from the filter bar after I applied the predicate! To avoid this, just create two array controllers and bind them both to the same NSMutableArray (just setting the content outlet won’t work).