One way of hearing about changes to the array controllers selectionIndexes
is to bind this property to an NSIndexSet
instance in your code somewhere, and then use the KVO design pattern to request a notification when this NSIndexSet
is altered. If you set this up correctly, when the user clicks on an unselected cell in your NSCollectionView
the NSIndexSet
that the array controller is using to store its selection indexes is updated. Since this index set is the one you're observing, you'll get a notification telling you about the change.
In the demo-app I created to answer this question, I placed the index set in question on the AppDelegate
- here's the implementation file:
// Interface ////////////////////////////////////////////////////////
@interface AppDelegate ()
// This is the content array from which the NSArrayController will derive
// it's arrangedObjects array
@property (nonatomic, strong) NSArray *collectionViewContent;
// This is the NSIndexSet that I want the NSArrayController to use
// to store its selectionIndexes.
@property (nonatomic) NSIndexSet *mySelectionIndexes;
@end
// Implementation //////////////////////////////////////////////////
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// The content that will be shown in the NSCollectionView (each word
// represents a single collection view item).
self.collectionViewContent = @[@"The", @"rain", @"in", @"Spain", @"falls", @"..."];
// Tell cocoa you want to know when the array controller makes changes to
// the index set it's using to stores its selection indexes
[self addObserver:self
forKeyPath:@"mySelectionIndexes"
options:0
context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
NSLog(@"Collection view selection just changed to: %@", self.mySelectionIndexes);
}
//////////////////////////////////////////////////////////////////
In the Bindings Inspector for the NSArrayController
you can now tell the array controller to use the AppDelegate
property mySelectionIndexes
to store its selection indexes:

If you're still experiencing problems, it's possible that you've gone wrong with the bindings somewhere else - here are all the bindings I used:
NSArrayController
The array controller will get it's content from an array managed by the AppDelegate
object. It will store it's selection indexes in an NSIndexSet
, also managed by the AppDelegate
- Content Array: App Delegate.collectionViewContent
- Selection Indexes: App Delegate.mySelectionIndexes
NSCollectionView
The collection view will get it's model data from the array controller. It will mark as selected those views that appear at the indexes stored in the array controller's selectionIndexes
property:
- Content: Array Controller.arrangedObjects
- Selection Indexes: Array Controller.selectionIndexes
Onto the view that was automatically generated when I dragged the NSCollectionView
onto the canvas, I've added one NSTextField
, this text field has just one binding:
- Value: Collection View Item.representedObject (In other words, type representedObject into the Model Key Path field.
A Final Word:
It's worth pointing out that you don't have to set up this binding. To get word when one of the items in your collection view is selected or unselected by the user, create a subclass of NSCollectionViewItem
and override the selected
setter. This property is called automatically each time an item is selected or unselected. In your implementation, you can now make adjustments to the item's view to take account of the fact that it's status has changed. In my demo-app, my custom subclass of NSCollectionViewItem
was called PPCollectionViewItem
:
@implementation PPCollectionViewItem
-(void)setSelected:(BOOL)selected {
// Call super...
[super setSelected:selected];
// ...now change the view associated with this item. Remember,
// the view is one of the cells in the NSCollectionView - I
// changed it from a standard NSView, to a subclass called
// CollectionViewCell which keeps a flag indicating whether
// or not it's selected (the drawRect routine is varied
// according to this flag's value).
[(CollectionViewCell *)self.view setDrawAsSelected:selected];
}
@end