How do you instantiate a NSCollectionViewItem from main Storyboard for use in a collectionView

1.8k Views Asked by At

I have a Storyboard that contains a controller with a NSCollectionView. The Storyboard also contains a NSCollectionViewItem with outlets connected to NSCollectionViewItem subclass, FeedItem.

enter image description here

How do you use the the "cell" or "scene" from the Storyboard (not a separate nib file) in the itemForRepresentedObjectAt method?

This is what I have so far..

  class FeedsController : NSViewController, NSCollectionViewDataSource {
  @IBOutlet weak var collectionView: NSCollectionView!

  override func viewDidLoad() {
    super.viewDidLoad()
  }

  func numberOfSections(in collectionView: NSCollectionView) -> Int {
    return 1
  }

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

  func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
    let collectionViewItem = self.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "FeedItem")) as! FeedItem

    collectionViewItem.urlLabel.stringValue = "http://www.seanbehan.com"
    collectionViewItem.entriesLabel.stringValue = "15 Entries"
    collectionViewItem.updatedLabel.stringValue = "Last Update: June 1st at 3:15PM"

    return collectionViewItem
  }
}

class FeedItem : NSCollectionViewItem {
  @IBOutlet weak var urlLabel: NSTextField!
  @IBOutlet weak var updatedLabel: NSTextField!
  @IBOutlet weak var entriesLabel: NSTextField!
}

It is a MacOS Cocoa app using Swift 4.1

3

There are 3 best solutions below

7
matt On

The docs are always worth glancing at:

You do this by calling the makeItem(withIdentifier:for:) method of the collection view to retrieve an empty item object of the appropriate type.

And as the docs further explain, to do that you will need to have registered a nib or a class with the collection view.

0
ailinykh On

The only way to instantiate NSCollectionViewItem from storyboard is itemProtorype which is deprecated at 10.14

If you still using an older SDK, you could do so

let itemIdentifier = NSStoryboard.SceneIdentifier(rawValue: "CollectionViewItemIdentifier")

if let item = NSStoryboard.main?.instantiateController(withIdentifier: itemIdentifier) as? NSCollectionViewItem {
    collectionView.itemPrototype = item
}

But I highly recommend to use .xib and methods described by Apple documentation:

Long story shorts you have to use .xib file for your NSCollectionViewItem

0
bshirley On

Storyboard Option

If you want to include the NSCollectionViewItem in the same storyboard as your NSCollectionView

  • Using the Library (plus symbol, upper right, cmd-shift-L), drag a NSCollectionViewItem onto (and empty area of) the canvas.
  • Using the Document Outline (left of canvas, menu: Editor->Document Outline), select the "Collection View Item" in the "Collection View Item Scene".
  • Using the Identity Inspector (right of canvas, cmd-option-4) assign the "Storyboard ID" to "MyCustomItem".
  • Optional: for reasonably complex items or for maintainability reasons, you may want to change the "Class" to a custom subclass.
  • It's non-intuitive, but NSCollectionViewItem is a subclass of NSViewController. In your implementation of NSCollectionViewDataSource implement…
    func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
        guard let item = self.storyboard?.instantiateController(withIdentifier: "MyCustomItem") as? NSCollectionViewItem else {
            return NSCollectionViewItem()
        }
        // …
        return item
    }

note: subclasses will want to change as? downcast class to their subclass

There is no need to use any of the register methods for this to work.