Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically created NSCollectionView `makeItem` returns nil even if registered

I am developing a macOS app targeting macOS 10.10 SDK and using Xcode 9.3 (Swift 4). I am not using xibs, but creating all views programmatically.

I want to create a NSCollectionView. I register a subclass of NSCollectionViewItem and then register that class to the NSCollectionView with a call to collectionView.register(:,forItemWithIdentifier). Later, in the data source, I call collectionView.makeItem(withIdentifier:,for:).

However the makeItem method always returns nil. What am I doing wrong?

I found a similar question but the solution is to call register, which I already do.

For reference, here's the minimum working to reproduce my the issue: when I put a breakpoint after the call to makeItem, I can see that the returned value is always nil.

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!


    func applicationDidFinishLaunching(_ aNotification: Notification) {
        window.contentViewController = TestViewController()
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }


}

let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "testIdentifier")

class TestViewController: NSViewController, NSCollectionViewDataSource {

    override func loadView() {
        self.view = NSView()
    }

    override func viewDidLoad() {
        let scroll = NSScrollView()

        self.view.addSubview(scroll)

        scroll.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: scroll, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
        NSLayoutConstraint(item: scroll, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 0).isActive = true
        NSLayoutConstraint(item: scroll, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0).isActive = true
        NSLayoutConstraint(item: scroll, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0).isActive = true
        NSLayoutConstraint(item: scroll, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 500).isActive = true
        NSLayoutConstraint(item: scroll, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 500).isActive = true

        let collection = NSCollectionView()
        scroll.documentView = collection

        collection.register(TestViewItem.self, forItemWithIdentifier: cellIdentifier)
        collection.dataSource = self
        collection.collectionViewLayout = NSCollectionViewFlowLayout()
        collection.reloadData()
    }

    func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
        let item = collectionView.makeItem(withIdentifier: cellIdentifier, for: indexPath)
        return item
    }
}

class TestViewItem: NSCollectionViewItem {

    override func loadView() {
        self.view = NSView()
    }
}
like image 455
Marco83 Avatar asked Oct 17 '25 11:10

Marco83


1 Answers

I think this is a bug. Workaround: set collectionViewLayout before registering the class.

Apparently the registered class is not stored if collectionViewLayout is not set. collectionViewLayout can be set to a new layout after registering the class, the registered class isn't removed.

like image 97
Willeke Avatar answered Oct 19 '25 01:10

Willeke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!