21
votes

When you drag a NSCollectionView to a view, a NSCollectionViewItem appears on the storyboard, floating around.

Imagine I drag several NScollectionViews to the same view. I will have a bunch of NSCollectionViewItems. How a collection view knows which NScollectionViewItem belongs to it? Is there a connection between the two that can be seen on interface builder? I don't see anything on interface builder? Where to do I see that?

EDIT: Apparently this seems to be a Xcode bug. When you add a NSCollectionView to the storyboard, it comes without a link to the NSCollectionViewItem and it seems to be impossible to connect the itemPrototype outlet between them.

After contacting Apple about bugs like this, their answer was: "this is a know issue with Storyboards on OS X. Use Xibs instead."

8
Bug still present in Xcode 6.3 6D570alecail
Bug still present in Xcode 7 Beta 6gbdavid
@CliftonLabrum - knowing Apple this will never be fixed.Duck
@green_knight I just tried to connect the itemPrototype reference outlet of an NSCollectionView to an NSCollectionViewItem sitting next to it in the same storyboard, and it won't connect. How did you do it?Clifton Labrum
apparently Apple don't give a crap about fixing this 3 years old bug.Duck

8 Answers

21
votes

Well, I gave @RubberDuck's workaround a go but it didn't work (see my comment). What worked for me is setting collectionView.itemPrototype in viewDidLoad of the view controller (Xcode 6.1):

@IBOutlet weak var collectionView: NSCollectionView!

override func viewDidLoad() {
    // don't forget to set identifier of CollectionViewItem 
    // from interface builder
    let itemPrototype = self.storyboard?.instantiateControllerWithIdentifier("collectionViewItem")
        as NSCollectionViewItem
    self.collectionView.itemPrototype = itemPrototype
}
4
votes

Yes, after hours struggling I confirm this one more of Xcode bugs.

The only solution is to edit the file Main.storyboard and add this line to the end of CollectionView section, just before </collectionView>:

<connections>
  <outlet property="itemPrototype" destination="XXXXXXX" id="Kaa-2J-b4e"/>
</connections>

where XXXXXX is the id or the CollectionViewItem. The other number and you can keep the one I post, unless this id is already used by your project, but the chances of this happens is very dim.

4
votes

I couldn't get the accepted answer from @mostruash to work in Objective-C either, but I came up with another workaround. Use a custom setter for the collectionView IBOutlet property:

- (void)setCollectionView:(NSCollectionView *)collectionView {
    NSCollectionViewItem *itemPrototype = [self.storyboard instantiateControllerWithIdentifier:@"collection_item"];
    collectionView.itemPrototype = itemPrototype;
    _collectionView = collectionView;
}
3
votes

Selected answer needs more information:

If you make binding from collectionView's content to array controllers arranged objects using Interface Builder's bindings, it will throw error: "NSCollectionView item prototype must not be nil".

This is because bindings are made before itemPrototype is assigned. Instead, make bindings with code after itemPrototype assignment.

@IBOutlet weak var collectionView: NSCollectionView!
@IBOutlet var arrayController: NSArrayController!
let itemPrototype = self.storyboard?.instantiateControllerWithIdentifier("collectionViewItem")
        as NSCollectionViewItem
self.collectionView.itemPrototype = itemPrototype
collectionView.bind("content", toObject: arrayController, withKeyPath: "arrangedObjects", options: nil)
2
votes

I fall in the same probleam, anyway since 10.11 Apple Documents says:

" You must also disconnect and discard the NSCollectionView’s “itemPrototype”, which is a vestige of the 10.10-and-earlier API model."

from: https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKit/#10_11CollectionView

here is explained how it works now.

So we must use old beloved XIBS:

NSCollectionViewItem *item = [collectionView makeItemWithIdentifier:@"Thing" forIndexPath:indexPath];
1
votes

The NSCollectionView has an outlet itemPrototype that's connected to its specific NSCollectionViewItem. You can see this in the Connections inspector for either object.

1
votes

Go to the Object Library (the bottom right of Xcode) and search for "Object". It "Provides an instance of an NSObject subclass that is not available in Interface Builder." Drag and drop that into the storyboard, onto the top bar of the ViewController (or alternatively under the ViewController in the tree-view on the LHS.) Then, click on that Object, and in the "Identity Inspector" set its class to be your ViewItem class. Then you can then ctrl+drag from the Collection View to the Object, and it will let you wire it up as "itemPrototype".

1
votes

Guys the trick seem to be that you cannot use a regular ViewController from the Object collection in Xcode when using Storyboards.

What works for me is dragging a collection view item from the Objects list and setting its class to your custom class then wiring up all the connections as you normally would to create IBOutlets.

Then you have to instantiate the view instead of makeView but this way allows you to use multiple views in the same collection without registering anything special.