objective-cmacosappkitnscollectionviewuicollectionviewcompositionallayout

Why is NSCollectionView not loading in Objective-C?


I am learning about NSCollectionView compositional layout on macOS (12.4, Xcode 13.4). In the Swift version of this app everything works as expected, yet when converting it to Objective-C, while I get everything to compile, the app loads as blank.
I checked the outlets in the nib file (dataSource and delegate from Collection View to File's Owner), checked the creation of a reusable item (I build it through a custom nib). The error I get in the console when the app launches is as follows:

2022-07-21 15:26:25.817911+0200 Cocoa Pr L68 ObjC[14203:1414415] *** Assertion failure in -[_NSCollectionViewCore _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:], UICollectionView.m:6488
2022-07-21 15:26:25.818378+0200 Cocoa Pr L68 ObjC[14203:1414415] could not dequeue an item of kind: NSCollectionElementKindItem with identifier _NS:8 - must register a nib or a class for the identifier, or name a nib or class to match the identifier

Browsing the docs, I learned that NSCollectionView doesn't have a dequeueReusable kind of method like Table Views in iOS have so the first error is not clear to me. The second is even stranger because I've actually register a class for the identifier:

#import "CollectionViewController.h"
#import "CollectionViewItem.h"

@interface CollectionViewController ()
@property (weak) IBOutlet NSCollectionView *collectionView;

@end

@implementation CollectionViewController
@synthesize collectionView;

- (void)viewDidLoad {
    [super viewDidLoad];
    CollectionViewItem *collectionViewItem = [[CollectionViewItem alloc] init];
    
    [collectionView registerClass:[NSCollectionViewItem class] forItemWithIdentifier:collectionViewItem.identifier];
    
    [collectionView setCollectionViewLayout:self.listLayout];
}

The listLayout method is defined afterwards in the same file. All NSCollectionViewDataSource methods are properly defined as in the Swift version, for reference:

- (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView *)collectionView {
    return 3;
}

- (NSInteger)collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 20;
}

- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath {
    NSCollectionViewItem *item = [collectionView makeItemWithIdentifier:collectionView.identifier forIndexPath:indexPath];
    [item.textField setStringValue:[NSString stringWithFormat:@"%ld, %ld", indexPath.section, indexPath.item]];
    
    return item;
}

The NSCollectionViewItem class is thus defined:

#import "CollectionViewItem.h"

@implementation CollectionViewItem

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.identifier = @"CollectionViewItemReuseIdentifier";
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

@end

I wonder what piece of the puzzle is missing as these errors, while apparently clear, seem to point to something that I have implemented. Have I implemented it wrong? Or not completely?
I would be very grateful to anyone shedding some light on all this.
Thank you


Solution

  • The registered class should be CollectionViewItem instead of NSCollectionViewItem. Change

    [collectionView registerClass:[NSCollectionViewItem class] forItemWithIdentifier:collectionViewItem.identifier];
    

    to

    [collectionView registerClass:[CollectionViewItem class] forItemWithIdentifier:collectionViewItem.identifier];
    

    It's in the error could not load the nibName: NSCollectionViewItem, but I'm so used to NS that I didn't notice.