Tuesday, 9 August 2011

NSCollectionView Redux

In the previous post on NSCollectionView I was unable to build the NSCollectionViewItem's NSView in Interface Builder so I built it by hand. Thanks to a post on Stack Overflow (http://stackoverflow.com/questions/6866798/binding-to-nscollectionviewitem-crashes-xcode/6961261#6961261) I was shown how to do it. So here it is in a fuller example.

Starting with the same data item we had the last time:


@interface Item : NSObject {
    NSString *title;
    NSInteger option;
}


@property (readwrite, copy) NSString *title;
@property (readwrite) NSInteger option;


- (id)initWithTitle:(NSString *)_title option:(NSInteger)_option;
@end

And creating a model in the application delegate in a similar way



- (id)init
{
    self = [super init];
    
    items = [[NSMutableArray alloc] init];
    
    int i;
    for (i = 0; i < 20; i++) {
        Item *item = [[Item alloc] initWithTitle:@"test" option:i];
        [items addObject:item];
    }
    
    return self;
}

In the MainMenu.xib when we drag an NSCollectionView into the window, it creates the NSCollectionViewItem and NSView automatically. This time, we only want to delete the NSView as we are going to create a new one.

Create a new file, select View from the User Interface category and name it what you will. In this view we can design our item. 


In this nib file, set the class type of the File's Owner to NSCollectionViewItem. This allows us to bind controls to the representedObject property of NSCollectionViewItem.


I bound the value of the label to representedObject.option and the value of the NSTextField to representedObject.title.


NSCollectionViewItem has a view outlet and this is used whenever it is asked which view is the main view. We need to set this by control dragging from the File's Owner placeholder to the Custom View object, and selecting view.



The final thing we need to do is to tell the NSCollectionViewItem which nibfile to load whenever it needs to create a new view. In the MainMenu.xib file, select the Collection View Item and display the Attributes Inspector. In the Nib Name dropdown either type or select the name of the custom View's nibfile.


Just before we build and run, we need to tell the NSCollectionView where to get its data from. Add an NSArrayController to the MainMenu.xib, and bind the content property of the NSCollectionView to the arrangedObjects property of the NSArrayController.


and bind the content array property of the NSArrayController to the model that we created in the application delegate.


Now if you build and run, the collection view should display the custom item:



It is good to know how to do this now, as doing it by hand felt clunky and awkward, especially to make a nice UI.


Links to the other parts of the NSViewController articles
Part 1:- http://comelearncocoawithme.blogspot.com/2011/07/nsviewcontrollers.html
Part 2:- http://comelearncocoawithme.blogspot.com/2011/07/nsviewcontrollers-part-2.html
Part 3:- http://comelearncocoawithme.blogspot.com/2011/08/nsviewcontrollers-part-3.html

4 comments:

  1. I truly believe I am losing my mind on this NSCollectionView. I have followed so many articles (even the ones on the apple developer site) but I can't get this working.

    Yours seems to be the most promising so far. But just before running the project I can't get what you are showing in your example. Bind to: Separate NIB App Delegate....

    How can I get that??? Cause no matter what I do my app will crash on run time with any of the other options. What am I missing???

    Also I had to change this in the -(id) init of Item.m to get my code working:

    - (id)init
    {
    self = [super init];

    NSMutableArray * items = [[NSMutableArray alloc] init];

    int i;
    for (i = 0; i < 20; i++) {
    Item *item = [[Item alloc] initWithTitle:@"test" option:i];
    [items addObject:item];
    }

    return self;
    }

    Maybe you can send me your projectile so I can see what I am doing wrong before I start talking to a coconut and naming it.....

    Thanks.

    Jory.

    mail: jory@jorydekort.nl

    ReplyDelete
  2. Never mind... I figured it out. It was to late last night to think clear. Thanks for the great work on your blog!!

    ReplyDelete
  3. Hi, I'm still getting the "NSCollectionView item prototype must not be nil" error. When you create the new .xib - does that contain an NSCollectionViewItem view or NSCollectionViewItem?

    ReplyDelete
  4. Adding objects to the NSMutableArray failed to add them to NSCollectionView. So I added them directly to the NSCollectionView and that seemed to work.

    Thanks.

    ReplyDelete