Swift Collection View: Phase 1/9

In this workshop series, you’ll learn how to use the UICollectionView class-the Swift way. Before you begin, I assume you already know how to code the Collection View using the Objective-C Programming Language. If not then read this six-part Collection View tutorial. It was written in the Objective-C Programming Language. In order to learn how to use the collection view, we’ll build an iOS application in phases. In each phase we will implement a new feature in the app.

Phase 1

This is phase 1 of the SwiftCollectionView workshop; in it, you will learn how to implement this feature in an iOS project we’ll create for this workshop series:

Display custom collection view cells in a single section of a collection view.

This QuickTime video shows what the collection view’s user interface will look like and how it will function, once you’ve implemented above mention feature in a new iOS project.

Create a New iOS Project

Without further due, let us get down to business and create a new iOS project.

  1. Launch the latest version of Xcode. Currently it is version 6.1.
  2. Select the Single View Application template.
  3. Provide options shown in Figure 1-1 for the project.
  4. On the final screen, make sure you tick the Source Control checkbox and select the Interactive Swift Programming folder, before you hit the Create button-see Figure 1-2 below.
swiftcv-fig1-1 swiftcv-figure1-2
Figure 1-1 Figure 1-2

Add A Class File in The Project

Now, you have to add a swift class file in the project. It will be a subclass of the UICollectionViewController class.

  1. Start by deleting the existing ViewController.swift class file from the Navigator panel.
  2. Click the + button located at the bottom of the Navigator panel, then select New File… from the pop up menu.
  3. Select the Cocoa Touch Class template-see Figure 1-3 below.
  4. Provide options shown in Figure 1-4 for the class file.
  5. Move the new file so that it is located in the SwiftCollectionView folder.
swiftcv-figure1-3 swiftcv-figure1-4
Figure 1-3 Figure 1-4

Design The App User Interface

You are ready to design the app user interface and connect it to its a swift class file; so click the Main.storyboard file to load it in Interface Builder.

  1. Drag a Collection View Controller from the Object Library, and drop it on the left side of the existing View Controller scene.
  2. In the Identity Inspector, connect the CollectionView Controller scene to the MasterViewController.swift class file-see Figure 1-5 below.
  3. Move the initial scene arrow from the View Controller scene and drop it on the left side of the Master View Controller scene. This make the Master View Controller scene the initial scene.
  4. Delete the View Controller scene.

From now on, I will refer to the storyboard scene as the Master scene and its class file as the Master class.

swiftcv-figure1-6
Figure 1-5

You are ready to design the Master scene.

  1. Click the collection view. In the Size Inspector, configure its attributes to what’s shown in Figure 1-6 below.
  2. You don’t have to do this step. Click the Collection View Cell and change its Background attribute, via the Attribute Inspector-see Figure 1-7.
  3. Click the Master scene and embed it in a Navigation Controller (Editor | Embed in | Navigation Controller).
  4. Click the Master scene’s Navigation Item. Its the blank bar above the Collection View.
  5. In the Attributes Inspector, enter Photos in the Title field.
  6. Click the Master scene’s Collection View Cell (yellow square).
  7. In the Attributes Inspector, enter Cell in the Identifier field. This eliminate both warning issues.
swiftcv-figure1-8 swiftcv-figure1-9
Figure 1-6 Figure 1-7

That’s all you have to do for the Master scene.

The App Assets

I want you to download this zip file. It has 5 images. The first four are App icons and you should put them in the appropriate iPhone and iPad placeholder slots. The fifth image will serve as theCollection View’s background.

download-images-icon

The Master Class File Code

So far, so good. Now, you are ready to add code in the Master class file to make its view look and function like the one shown in the QuickTime video.

Click the Master class file to load it in the code editor. Now, add code shown in Listing 1 in the file’s viewDidLoad() function.

Listing 1: MasterViewController.swift/viewDidLoad()

override func viewDidLoad() {
  super.viewDidLoad()
  // Set the collection view's backgroundcolor to display an image
  self.collectionView!.backgroundColor = UIColor(patternImage: UIImage(named: "purty_wood")!)
}

After entering above code in the viewDidLoad() function, run the app in the iPhone or iPad Simulator.

Ok, the collection view have a background. It is time to implement this feature of the UICollectionView class: Display custom collection view cells in a single section of a collection view.

To implement above feature in the Xcode project, you have to add a new class file called, PhotoCell in the project. You’ll use it in in Master class file to create collection view cells for the Master view’s collection view. Here is a diagram of the class and instructions to create it.

photocell-class-diagram

  1. Click the + button, located at the bottom of the Navigator panel and select New File…
  2. Select the Cocoa Touch Class template, before clicking the Next button.
  3. Provide information shown in the image below for the class.

swiftcv-figure1-13

Now that you’ve created the PhotoCell class file, add code shown in Listing 2 in it.

Listing 2: PhotoCell.swift class file code

import UIKit

class PhotoCell: UICollectionViewCell {
    // The collection view cell's objects
    var imageView: UIImageView!
    var caption: UILabel!

    // This init function prevent the compiler from complaining
    required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }

  // This init function is executed, every time you create an instance of this class
  override init(frame: CGRect) {
    super.init(frame: frame)

    // Configure the the ImageView object and add it to the collection view's contentView container
    imageView = UIImageView(frame: CGRect(x:30, y:12, width:55, height:55))
    imageView.contentMode = UIViewContentMode.ScaleAspectFill
    contentView.addSubview(imageView)

    // Configure the Label object and add it to the collection view's contentView container
    let textFrame = CGRect(x:5, y:67, width:100, height:35)
    caption = UILabel(frame: textFrame)
    caption.font = UIFont.systemFontOfSize(14.0)
    caption.textAlignment = .Center
    caption.numberOfLines = 2
    caption.lineBreakMode = NSLineBreakMode.ByWordWrapping
    caption.textColor = UIColor.whiteColor()
    caption.backgroundColor = UIColor.blackColor()
    contentView.addSubview(caption)
  }
}

As you can see the PhotoCell class code is pretty straight forward. What you have to do now is update code in the MasterViewController.swift file’s viewDidLoad() function-see Listing 3.

List 3: MasterViewController.swift/viewDidLoad() function

let reuseIdentifier = "Cell"

class PhotosViewController: UIViewController {

  // Collection view dataSource objects
  var icon: PhotoCell!
  var imageFileNames = [String]()

  override func viewDidLoad() {
  super.viewDidLoad()

  // Set the collection view's backgroundcolor to display an image
  self.collectionView!.backgroundColor = UIColor(patternImage: UIImage(named: "purty_wood")!)

  // Register the class with the collection view
  self.collectionView!.registerClass(PhotoCell.self, forCellWithReuseIdentifier: reuseIdentifier)

  // Add objects in the collection view dataSource, imageFileNames Array
  self.loadImages()
}

The viewDidLoad() function calls the loadImages() function. Listing 4 shows the code implement it in the MasterViewController.swift file.

List 4: MasterViewController.swift/ loadImages() function code

// Get images from the app bundle and put them in the cv dataSource object
func loadImages() {
  // Get reference to the app's main bundle
  var mainBundle: NSBundle = NSBundle.mainBundle()

  // Fetch all jpg image files from the main bundle
  var results:NSArray = mainBundle.pathsForResourcesOfType("jpg",inDirectory:nil)

  // Convert NSArray to Swift Array
  var dirPaths: Array = results as AnyObject as [String]

  for path in dirPaths {
    // Convert the String values stored in path to an array
    var objectArray = path.componentsSeparatedByString("/")

    // Remove last the object from the objectArray and put it the imageFileNames variable
    imageFileNames.append(objectArray.removeLast())
  }
  /**************** DEBUG CODE ************/
  println(imageFileNames)
  println(imageFileNames.count)
  /****************************************/
}

Download this zip file. It contain photos the loadImages() function will load in the collection view’s dataSource object; which is called, imageFileNames.

download-images-icon

After unzipping the file, go to Xcode and create a sub folder in the SwiftCollection folder. Call it flowers. Copy the unzipped file’s images to the folder. Now is a good time to use Xcode’s Source Control | Commit menu to save changes made so far, to the project files.

Moving along, add code shown in Listing 5 in the MasterViewController.swift file. They are the collection view’s dataSource functions.

Listing 5: MasterViewController.swift class file code

// MARK: UICollectionViewDataSource

override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
  // Return the number of sections
  return 1
}

override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  // Return the number of items in the section
  return imageFileNames.count
}

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  // Initialize the reusable Collection View Cell with our custom class
  icon = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as PhotoCell

  //Configure the collection view cell
  var imageFile = imageFileNames[indexPath.row]
  icon.imageView.image = UIImage(named: imageFile)
  var stringArray: Array = imageFile.componentsSeparatedByString(".")
  icon.caption.text = stringArray[0]

  // Return the cell
  return icon
}

After entering above code in the MasterViewController.swift file, run the app in the iPhone and iPad simulators. The app’s user interface should look like the one shown in above QuickTime video.

That’s All Folks!

That’s it for phase 1 of the Swift Collection View workshop. Next week, you will work on phase 2 of the Swift Collection View workshop to implement this feature of the UICollectionView class: select a cell in the collection view. Until then, happy coding! 🙂

  • Piyush Sharma

    where you have added delete button property in PhotoCell?

  • Immyfly

    var objectArray = path.characters.split(“/”).map { String($0) }

    var stringArray = imageFile.characters.split(“.”).map { String($0) }

    for swift 2.0 rather then using component separated by string

    var objectArray = path.componentsSeparatedByString(“/”)

    var stringArray: Array = imageFile.componentsSeparatedByString(“.”)

    works perfectly regards

  • Jim Atwood

    Got it! Whew! There were quite a few missing steps in your article, but I finally figured everything out. It was a great exercise, but word of caution to new viewers, the code in this article isn’t complete. I highly recommend attaching the swift files so that users can view the missing info. Thanks for the great article otherwise as it truly helped me to get started. Much appreciated. Now I’m onto Phase 2.

  • Jim Atwood

    Hello! Thanks so much for the excellent tutorial. Unfortunately I’m getting several errors in List 3. Both “self.collectionView.backgroundColor” and “self.collectionView.registerClass” are not working with xCode 6.1.1 and Swift with iOS8. Also without any “var selectedPhotoName”, the code breaks big time. Is there some code you may have left out in the article? Is there a project demo file available? What you are covering is excellent info, it’s just not either up to date or something is missing. Thanks very much and again fantastic work!!

    • Jim Atwood

      Yeah, I think if you could provide either the swift files or the project code for Phase 1, that would be great for working through the rest of the Phases. If anyone tries Phase one, their going to be dead in the water due to the errors. I fixed a couple of issues, but am still having problems with the registerClass and backgroundColor code. Even if I use a ? or ! it’s not working. Strange! Thanks again.

    • Jim Atwood

      Errors:
      return imageFileNames.count
      Use of unresolved identifier ‘imageFileNames’

      Another issue is your “override func collectionView” is not working.

      Method does not override any method from its superclass.

      self.collectionView.backgroundColor ….
      ‘(UICollectionView, numberOfitemsinSection: Int) -> Int’ does not have a member named ‘backgroundColor’
      Note: Same error for self.collectionView.registerClass

      As I mentioned earlier, the main problems are with unresolved identifier “imageFileNames” in the MasterViewController.swift file. In addtion, the “override func” is giving error whereas using just “func” stops the errors. Finally self.collectionView code gives “does not have a member” errors.

      I could also send you my MasterViewController.swift file if you like. Thanks – Jim

    • Jim Atwood

      Sorry for the flood of comments. I managed to find one error in my code which was that I forgot to add “var imageFileNames = [String]()”. That fixed most of my errors. However, I’m still getting the override func error and the self.collectionView.backgroundColor and registerClass errors. I’m now down to 4 errors in total. IF I change from override func to just func AND comment out the self.collectionView lines, I can get the app to build successfully. I then have the problem of getting a black screen when testing on my iPhone.

      I’ll keep at it. Thanks again.

    • Hey Jim thanks for the comments. First of all the reason you’re getting the override func errors is because the MasterViewController.swift class is not a subclass of the UICollectionViewController class. See Figure 1-4 in the section, ‘Add A CLASS FILE IN THE PROJECT’. Also make sure you drop a ‘Collection View Controller’ on the storyboard. Not a ‘Collection View’

      In Xcode 6.1.1, you have to change reference to collectionView in the viewDidLoad() function to this: self.collectionView!.backgroundColor … and this: self.collectionView!.registerClass(…
      The code should work after making these minor changes. I updated the post’s code to reflect these changes.

      Make sure you declare the ‘selectedPhotoName’ variable above the viewDidLoad() function like so:
      var selectedPhotoName = String()

    • Hey Jim thanks for the comments. First of all the reason you’re getting the override func errors is because the MasterViewController.swift class is not a subclass of the UICollectionViewController class. See Figure 1-4 in the section, ‘Add A CLASS FILE IN THE PROJECT’. Also make sure you drop a ‘Collection View Controller’ on the storyboard. Not a ‘Collection View’

      In Xcode 6.1.1, you have to change reference to collectionView in the viewDidLoad() function to this: self.collectionView!.backgroundColor … and this: self.collectionView!.registerClass(…
      The code should work after making these minor changes. I updated the post’s code to reflect these changes.

      Make sure you declare the ‘selectedPhotoName’ variable above the viewDidLoad() function like so:
      var selectedPhotoName = String()