Swift Collection View: Phase 7/9

So far, you learned how to implement these features in the SwiftCollectionView application:

In this phase of the SwiftCollectionView workshop, you will learn how to:

  • Fetch image urls from a plist file, add them in the collection view’s dataSource variable.
  • Load the photo urls’ images in the collection view cells.

I moved the photos that’s loaded in the collection view cells to the server that’s hosting theapplady website. In addition to this, I created a plist file and adding the photo urls in it. This mean you’ll have to download the plist file and put it in the SwiftCollectionView project. You’ll have to change code in these class files as well: MasterViewController.swift and DetailViewController.swift.

Ok, the first thing I want you to do is download and unzip this file phase7-files. The table below describe its content.

photos.plist – This plist file holds 46 photo urls and the image below shows a partial view of its of those urls. We’ll create a function in the MasterViewController.swift file to fetch the plist file’s data and load them in the collection view’s dataSource object; which will be a Swift array variable called cvDataSource.
swiftcv-phase7-3
JKTImageCacheLibrary.swift – This is a third-party class file (source: https://www.facebook.com/ryanjohny2k/posts/397914933681310). We’ll create an instance of the class and use its setImage() function in the collectionView’s cellForItemeAtIndexPath() function. The setImage() function will download the url’s image in the background while you interact with the app’s user interface. While the function is downloading the images, you’ll see the placeholder512 image in collection view cells. Over it, you see an animated activity indicator view. Take a look at the image below. It shows what the place holder image and the activity indicator view will look like while the app is downloading an image in the background. The image also shows what the cell will look like once the setImage() function finish loading an url’s image in a cell of the collection view.swiftcv-figure7-4
placeholder512.png – This image will server as a cell’s placeholder image; while the setImage() function downloads the photo urls’ images in the background. It looks like this:
placeholder512

Above table gives you a pretty good idea of what you will accomplish in this phase of the SwiftCollectionView workshop. Let’s get to work shall we?

Create A New Branch

Launch the SwiftCollectionView project in Xcode. Use the Source Control menu to switch to the branch, highlight-collection-cell-tapped. Next, use the Source Control menu to create a new branch called, collection-view-plist.

House Keeping Tasks

Before you get started in modifying the SwiftCollectionView project’s class files’ code, you have to perform a few “housekeeping” tasks.

If you haven’t done so already, unzip the file you downloaded earlier. Put both the photos.plist file and the JKTImageCacheLibrary.swift files in the SwiftCollectionView project’s Supporting Files folder. Next, put the placeholder512.png file in the Images.xcassets folder.

The final housekeeping task you have to do is, delete the flowers folder from the project navigator panel. Before continuing, use the Source Control’s Commit menu item to commit changes you made to the project. That’s it, you’re ready to rock!

The Photos User Interface Code

You have to change code in the MasterViewController.swift file. Start by replacing the variable declaration code with these:

class MasterViewController: UICollectionViewController {

  @IBOutlet weak var editButton: UIBarButtonItem!
  var editModeEnabled = false
  var icon: PhotoCell!
  var cvDataSource = [String]()
  var selectedPhotoUrl = String()
  var imageCache = JKTImageCacheLibrary()

Now, here’s the code to implement a function that’ll fetch photo urls from the photos.plist file and add them in the collection view’s dataSource variable called, cvDataSource. Put code shown below at the end of the MasterViewController.swift file.

func fetchPlistData() {
  // Fetch data from the plist file and put it in an Objective-C dictionary
  let path = NSBundle.mainBundle().pathForResource("photos", ofType: "plist")
  var dict = NSDictionary(contentsOfFile: path!)!

  // Put the dictionary entries in the collection view's dataSource object
  photoUrls = dict["flowers"] as [String]

  /******************* DEBUG CODE ********************/
  for var i=0; i < cvDataSource.count; ++i {
    println("\(i+1). \(cvDataSource[i])")
  }
  println("\nTOTAL PHOTO URLS: \(cvDataSource.count)")
  /****************************************************/
}

Next, locate the viewDidLoad() function and replace the loadImages() statement with code shown below; also, delete the loadImages() function code.

// Add objects in the collection view dataSource object
fetchPlistData()

From this point, you’ll modify remaining code in the MasterViewController.swift file to stop the compiler from complaining and to populate the collection view cells. Start by replacing the last to lines in the prepareForSegue() function with these:

// Pass the selectedPhotoUrl to the destination view controller
controller.selectedPhotoUrl = selectedPhotoUrl

Locate the numberOfItemsInSection() function and change the return statement to this:

return cvDataSource.count

Change line 76 in the cellForItemAtIndex() function to this:

var imageFile = cvDataSource[indexPath.row]

Next, change line 102 in the didSelectItemAtIndexPath() function to this:

selectedPhotoUrl = cvDataSource[indexPath.row] as String

Finally, change line 113 in the deletePhotoCell() function to this:

cvDataSource.removeAtIndex(i)

Xcode no longer complain. Now; before you run the app in the iOS Simulator, locate the cellForItemAtIndexPath() function and change its code to this:

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 imageUrl = cvDataSource[indexPath.row]
  imageCache.setImage(icon.imageView, imgUrl: imageUrl)

  // Convert the string variable (currentLink) to an Array variable (stringArray)
  var stringArray: Array = imageUrl.componentsSeparatedByString("/")

  // Remove the last element (i.e white-rose.jpg) from the stringArray and put it in a string variable (link)
  var element = stringArray.removeLast()

  // Convert the string variable (link) to an Array variable (stringObjectArray)
  var stringObjectArray = element.componentsSeparatedByString(".")
  icon.caption.text = stringObjectArray[0]

  if self.navigationItem.rightBarButtonItem!.title == "Edit" {
    icon.deleteButton.hidden = true
  } else {
    icon.deleteButton.hidden = false
    icon.shakeIcons()
  }

  // Give the delete button an index number
  icon.deleteButton.layer.setValue(indexPath.row, forKey: "index")

  // Add an action function to the delete button
  icon.deleteButton.addTarget(self, action: "deletePhotoCell:", forControlEvents: UIControlEvents.TouchUpInside)

  // Return the cell
  return icon
}

Notice how the JKTImageCacheLibrary’s setImage() function was used to load an image in the collection view cells’ imageView control. Also, notice how we we initialized the cell’s label control with a photo file’s name.

Test The Photos User Interface

Now is a good time as any to test the Photos user interface in one of the iOS Simulator. You should see output shown in images below, on the iOS Simulator’s screen and Xcode’s Debugger window.

swiftcv-figure7-5 swiftcv-figure7-2
Figure 7-1: Output in the iPhone 4s Simulator Figure 7-2: Output in the Debugger window

The Photo Detail Code

The only thing you have to do now is modify the PhotoDetailViewController.swift file’s code to look like this:

import UIKit
<pre>class PhotoDetailViewController: UIViewController {
  @IBOutlet weak var imageView: UIImageView!
  @IBOutlet weak var captionLabel: UILabel!
  var selectedPhotoUrl: String = ""

  override func viewDidLoad() {
    super.viewDidLoad()

    // Initialize this view controller's views
    imageView.image = UIImage(named: selectedPhotoUrl)

    // Convert the selectedPhoto string object to an Array
    var stringArray: Array = selectedPhotoUrl.componentsSeparatedByString(".")

    // Get the last element of the stringArray object and assign it to the captionLabel control
    captionLabel.text = stringArray[0]
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
}

Test The Photo Detail User Interface

Before testing the Photo Detail user interface in the iOS Simulator; comment out the Debugger code in the MasterViewController.swift file’s fetchPlistData() function. Next, use Xcode’s Source Control menu to commit changes made to the project. Now; the image below shows what the Photo Detail view should look like, when you click a cell in the collection view.

swiftcv-figure7-6

That’s it; you are with Phase 7 of the SwiftCollectionView application. Next, week you will learn how to do the following:

  • Display the number of selected cells in the navigation bar
  • Share selected collection view cell’s photo with friends

Until then, happy coding! 🙂