0

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

NotationMaster
  • 390
  • 3
  • 17
  • What is `collectionView.identifier` in `collectionView:itemForRepresentedObjectAtIndexPath:`? – Willeke Jul 21 '22 at 13:55
  • That needed to be `collectionViewItem`, not `collectionView`, but now that I changed the CollectionViewItem.h to have a property `itemID`, synthesised it in the implementation file and initialise it inside of the `super init` portion, something is still not working. I added `[[[CollectionViewItem alloc] init] itemID]` instead of `collectionView.identifier` and now the error is `could not load the nibName: NSCollectionViewItem in bundle NSBundle` followed by the path on disk and `(loaded)` I feel we're near the solution! – NotationMaster Jul 21 '22 at 14:07
  • Scrap all the `itemID` portion, it doesn't improve anything at all. I've changed approach, created an `NSCollectionViewItem` object inside of `CollectionViewController.m` and used `self.collectionViewItem.identifier` in both places `viewDidLoad` and `-collectionView:itemForRepresentedObjectAtIndexPath:` but the error is still `could not load the nibName in bundle`. – NotationMaster Jul 21 '22 at 14:14
  • What is in the custom nib and what is its name? – Willeke Jul 21 '22 at 20:56
  • Just saw this before signing off for the night. Here you can see the whole project: https://github.com/Cellomaster87/Apple-Programming-YT/tree/main/Cocoa%20Programming/Cocoa%20Pr%20L68%20ObjC There's a custom view, a custom box inside. All this works in Swift. At the folder up one level in the link tree you can also find the same project in Swift, just in case it may be useful. – NotationMaster Jul 21 '22 at 21:08
  • The link doesn't work. – Willeke Jul 22 '22 at 10:48
  • Just clicked on it, it opens normally to me. – NotationMaster Jul 22 '22 at 11:07
  • I get page not found and Apple-Programming-YT is not visible on https://github.com/Cellomaster87?tab=repositories – Willeke Jul 22 '22 at 12:13
  • I see it is set to Private, thank you for making me notice. I have now set it up as Public. In the meantime, I have zipped the project and uploaded to iCloud Drive. You can find it here: https://www.icloud.com/iclouddrive/05bvZfOoCldrd6Y90LktBhhpQ#Cocoa_Pr_L68_ObjC — forgive the hassle, please! – NotationMaster Jul 22 '22 at 12:37

1 Answers1

1

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.

Willeke
  • 14,578
  • 4
  • 19
  • 47