3

I am trying to nest NSCollection view inside of one another. I have tried to create a new project using the Apple Quick Start Guide as a base.

I start by inserting a collection view into my nib, to the view that is automatically added I drag another collection view onto it. The sub-collection view added gets some labels. Here is a picture of my nib:

completed nib

I then go back and build my models: My second level model .h is

@interface BPG_PersonModel : NSObject

@property(retain, readwrite) NSString * name;
@property(retain, readwrite) NSString * occupation;

@end

My First level model .h is:

@interface BPG_MultiPersonModel : NSObject

@property(retain, readwrite) NSString * groupName;
@property(retain,readwrite) NSMutableArray *personModelArray;

-(NSMutableArray*)setupMultiPersonArray;

@end

I then write out the implementation to make some fake people within the first level controller(building up the second level model): (edit) remove the awakefromnibcode

/*- (void)awakeFromNib {

    BPG_PersonModel * pm1 = [[BPG_PersonModel alloc] init];
    pm1.name = @"John Appleseed";
    pm1.occupation = @"Doctor";

    //similar code here for pm2,pm3

    NSMutableArray * tempArray = [NSMutableArray arrayWithObjects:pm1, pm2, pm3, nil];
    [self setPersonModelArray:tempArray];

} */


-(NSMutableArray*)setupMultiPersonArray{
    BPG_PersonModel * pm1 = [[BPG_PersonModel alloc] init];
    pm1.name = @"John Appleseed";
    pm1.occupation = @"Doctor";

    //similar code here for pm2,pm3


    NSMutableArray * tempArray = [NSMutableArray arrayWithObjects:pm1, pm2, pm3, nil];
    return tempArray;
}

Finally I do a similar implementation in my appdelegate to build the multiperson array

- (void)awakeFromNib {

    self.multiPersonArray = [[NSMutableArray alloc] initWithCapacity:1];

    BPG_MultiPersonModel * mpm1 = [[BPG_MultiPersonModel alloc] init];
    mpm1.groupName = @"1st list";
    mpm1.personModelArray = [mpm1 setupMultiPersonArray];

(I'm not including all the code here, let me know if it would be useful.)

I then bind everything as recommended by the quick start guide. I add two nsarraycontrollers with attributes added to bind each level of array controller to the controller object

I then bind collectionview to the array controller using content bound to arrangedobjects

Finally I bind the subviews:

with the grouptitle label to representedobject.grouptitle object in my model

then my name and occupation labels to their respective representedobjects

I made all the objects kvo compliant by including the necessary accessor methods

I then try to run this app and the first error I get is: NSCollectionView item prototype must not be nil.

(edit) after removing awakefromnib from the first level model I get this

enter image description here

Has anyone been successful at nesting nscollection views? What am I doing wrong here? Here is the complete project zipped up for others to test:

http://db.tt/WPMFuKsk

thanks for the help

EDITED:

I finally contacted apple technical support to see if they could help me out. Response from them is:

Cocoa bindings will only go so far, until you need some extra code to make it all work.

When using arrays within arrays to populate your collection view the bindings will not be transferred correctly to each replicated view without subclassing NSCollectionView and overriding newItemForRepresentedObject and instantiating the same xib yourself, instead of using the view replication implementation provided by NSCollectionView.

So in using the newItemForRepresentedObject approach, you need to factor our your NSCollectionViewItems into separate xibs so that you can pass down the subarray of people from the group collection view to your inner collection view.

So for your grouped collection view your override looks like this:

- (NSCollectionViewItem *)newItemForRepresentedObject:(id)object 
{ 
BPG_MultiPersonModel *model = object; 
MyItemViewController *item = [[MyItemViewController alloc] initWithNibName:@"GroupPrototype" bundle:nil]; 
item.representedObject = object; 
item.personModelArray = [[NSArrayController alloc] initWithContent:model.personModelArray]; 
return item; 
} 

And for your inner collection subclass your override looks like this:

- (NSCollectionViewItem *)newItemForRepresentedObject:(id)object 
{ 
PersonViewController *item = [[PersonViewController alloc] initWithNibName:@"PersonPrototype" bundle:nil]; 
item.representedObject = object; 
return item; 
}

here is a sample project that they sent back to me -

http://db.tt/WPMFuKsk

I am still unable to get this to work with my own project. Can the project they sent back be simplified further?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Prasanth
  • 646
  • 6
  • 21

1 Answers1

1

Please take a closer look at this answer

Short answer: Extracting each NSView into its own .xib should solves this issue.

Extended: The IBOutlet’s specified in your NSCollectionViewItem subclass are not connected when the prototype is copied. So how do we connect the IBOutlet’s specified in our NSCollectionViewItem subclass to the controls in the view?

Interface Builder puts the custom NSView in the same nib as the NSCollectionView and NSCollectionViewItem. This is dumb. The solution is to move the NSView to its own nib and get the controller to load the view programmatically:

  • Move the NSView into its own nib (thus breaking the connection between the NSCollectionViewItem and NSView).
  • In I.B., change the Class Identity of File Owner to the NSCollectionViewItem subclass.
  • Connect the controls to the File Owner outlets.
  • Finally get the NSCollectionViewItem subclass to load the nib:

Usefull links:

  1. how to create nscollectionview programatically from scratch
  2. nscollectionview tips
  3. attempt to nest an nscollectionview fails
  4. nscollectionview redux
Community
  • 1
  • 1
Gomino
  • 12,127
  • 4
  • 40
  • 49
  • I tried to do this and was able to get the collectionview to show properly, but not the nested one. The other issue I had was that since the main array itself is an array of arrays (multiperson containing sets of people from example above) how do I bind this data and pass it down to the nested individual view. – Prasanth Oct 05 '14 at 15:50