NSCollectionView Tutorial

In this NSCollectionView tutorial for macOS, you’ll learn how to add a collection view to your app and populate it with a data source – using Swift! By Gabriel Miro.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Creating a Collection View Item

Now you need to create an NSCollectionViewItem subclass to display your data elements.

Go to File/New/File…, select macOS/Source/Cocoa Class and click Next.

Set the Class field to CollectionViewItem, the Subclass of field to NSCollectionViewItem, and check Also create XIB for user interface.

CreateColViewItems

Click Next, and in the save dialog, select Controllers from Group and click Create.

Open CollectionViewItem.swift and replace the entire class with this:

import Cocoa
class CollectionViewItem: NSCollectionViewItem {

  // 1
  var imageFile: ImageFile? {
    didSet {
      guard isViewLoaded else { return }
      if let imageFile = imageFile {
        imageView?.image = imageFile.thumbnail
        textField?.stringValue = imageFile.fileName
      } else {
        imageView?.image = nil
        textField?.stringValue = ""
      }
    }
  }
  
  // 2
  override func viewDidLoad() {
    super.viewDidLoad()
    view.wantsLayer = true
    view.layer?.backgroundColor = NSColor.lightGray.cgColor
  }
}

In here, you do the following:

  1. Define the imageFile property that holds the model object to be presented in this item. When set, its didSet property observer sets the content of the item’s image and label.
  2. Change the background color of the item’s view.

Add Controls to the View

When you created CollectionViewItem.swift you selected “Also create a XIB” which produced the CollectionViewItem.xib nib file. For sake of order, drag the nib to the Resources group just below Main.storyboard.

The View in the nib is the root view for a subtree of controls to be displayed in each item. You’re going to add an image view for the slide and a label for the file name.

Open CollectionViewItem.xib.

Add an NSImageView:

  1. From the Object Library, add an Image View to View.
  2. Click Pin from the Auto Layout toolbar to set its constraints.
  3. Set the top, leading and trailing constraints to 0, the bottom to 30. Choose Update Frames: Items of New Constraints and click Add 4 Constraints.

ImageAL1

ImageAL2

Add a label:

LabelInPlace

Screen Shot 2015-12-09 at 20.11.30

  1. From the Object Library, add a Label below the Image View.
  2. Click the Pin button. Set the top, bottom, trailing and leading constraints to 0. Choose Update Frames: Items of New Constraints and click Add 4 Constraints.

Select the Label, and in the Attributes Inspector set the following attributes:

  1. Alignment to center
  2. Text Color to white
  3. Line Break to Truncate Tail

ConfigLabel

Add a CollectionViewItem to the Nib and Connect the Outlets

Though the File’s Owner in the nib is of the type CollectionViewItem, it is simply a placeholder. When the nib is instantiated, it must contain a “real” single top-level instance of NSCollectionViewItem.

Drag a Collection View Item from the Object Library and drop it into Document Outline. Select it, and in the Identity Inspector, set its Class to CollectionViewItem.

TopLevelObject

In the CollectionViewItem.xib, you need to connect the view hierarchy to the outlets of CollectionViewItem. In the xib:

  1. Select Collection View Item and show the Connections Inspector.
  2. Drag from the view outlet to the View in the Document Outline
  3. In the same way, connect the imageView and textField outlets to Image View and Label in the Document Outline

ConnectItemOutlets

Populate the Collection View

You need to implement the data source protocol so the view knows the answers to these questions:

  1. How many sections are in the collection?
  2. How many items are in each section?
  3. Which item is associated with a specified index path?

Open ViewController.swift and add the following extension at the end of the file:

extension ViewController : NSCollectionViewDataSource {
  
  // 1
  func numberOfSections(in collectionView: NSCollectionView) -> Int {
    return imageDirectoryLoader.numberOfSections
  }
  
  // 2
  func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
    return imageDirectoryLoader.numberOfItemsInSection(section)
  }
  
  // 3
  func collectionView(_ itemForRepresentedObjectAtcollectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
    
    // 4
    let item = collectionView.makeItem(withIdentifier: "CollectionViewItem", for: indexPath)
    guard let collectionViewItem = item as? CollectionViewItem else {return item}
    
    // 5
    let imageFile = imageDirectoryLoader.imageFileForIndexPath(indexPath)
    collectionViewItem.imageFile = imageFile
    return item
  }
  
}
  1. When your app doesn’t support sections, you can omit this method because a single section will be assumed.
  2. This is one of two required methods for NSCollectionViewDataSource. Here you return the number of items in the specified section.
  3. This is the second required method. It returns a collection view item for a given indexPath.
  4. This method instantiates an item from a nib where its name equals the value of the identifier parameter. It attempts to reuse an unused item of the requested type, and if nothing is available it creates a new one.
  5. Gets the model object for the given IndexPath and sets the content of the image and the label.
Note: The ability of the collection view to recycle unused collection view items provides a scalable solution for large collections. Items associated with model objects that aren’t visible are the objects that get recycled.

Set the Data Source

Your next step is to define the data source.

Open Main.storyboard and select the collection view.

Open the Connections Inspector and locate dataSource in the Outlets section. Drag from the adjacent button to the View Controller in Document Outline View.

SetAsDataSource

Build and run, and your collection view should display images from the Desktop Pictures folder:

OneSectionFinal

Voilà! It was worth all that work!

Troubleshooting

If you don’t see images, then you probably just missed something small.

  1. Are all the connections in the Connections Inspector set as instructed?
  2. Did you set the dataSource outlet?
  3. Did you use the right type for custom classes in the Identity Inspector.
  4. Did you add the top level NSCollectionViewItem object and change its type to CollectionViewItem?
  5. Is the value for the identifier parameter in makeItemWithIdentifier identical to the nib name?

Loading Items When the Model Changes

To display images from a folder other than the system’s Desktop Pictures folder, select File/Open Another Folder… and choose a folder that has image formats such as jpg or png.

But nothing seems to change in the window — it still displays the images from the Desktop Pictures folder. Although when you look at the console log, you can see the file names are from the new folder.

To refresh the collection view’s visible items, you need to call its reloadData() method.

Open ViewController.swift and add this code to the end of loadDataForNewFolderWithUrl(_:):

collectionView.reloadData()

Build and run. You’ll now have the correct images displayed in the window.

Gabriel Miro

Contributors

Gabriel Miro

Author

Zoltán Matók

Tech Editor

Chris Belanger

Editor

Michael Briscoe

Final Pass Editor and Team Lead

Over 300 content creators. Join our team.