Group Group Group Group Group Group Group Group Group Forums

Video Tutorial: Collection Views Part 1: Getting Started

In this video tutorial, you'll learn about the three most important components in collection views: the controller, the layout, and the data source object.

This is a companion discussion topic for the original entry at

Hi, just started with this CollectionView series, great stuff so far. I get an error in PapersDataSource though (Xcode 7.2.1):

error: ‘contains’ is unavailable: call the ‘contains()’ method on the sequence

Any idea how to fix this?

Another question: Do you guys have a video tutorial on how to use PList as a data source and how to parse it?

Edit: I found the solution myself with Google, sorry for not trying first myself. ^^ It is actually a very easy fix. Just a small syntax change:

if !sections.contains(section) {

By the way, I’m new to the subscribers section. So I’m not sure where to post questions, here or in the archive forum thread.

Cheers! Benny


I’m glad you were able to resolve the issue. Just to let you know that the series is currently being updated for Swift 2.1, so keep your eyes peeled for that when it’s released.

And this is absolutely the right place to be asking these questions. :smile:

Finally, to answer your question, we have a video series covering all the different approaches you can take to loading and saving data on iOS, including an entire video dedicated to just plists. You can find it here: Saving Data in iOS


Thanks Mic! I’ve just completed the custom cell part, so far so good. Love the challenges!
Really glad I signed up for the subscribers section. :smile:

Here’s an updated PapersDataSource.swift with all the adjustments I had to make to get it to compile in Swift 2.1 (Xcode 7.2.1):

import UIKit

class PapersDataSource {
  private var papers: [Paper] = []
  private var immutablePapers: [Paper] = []
  private var sections: [String] = []
  var count: Int {
    return papers.count
  var numberOfSections: Int {
    return sections.count
  // MARK: Public
  init() {
    papers = loadPapersFromDisk()
    immutablePapers = papers
  func deleteItemsAtIndexPaths(indexPaths: [NSIndexPath]) {
    var indexes: [Int] = []
    for indexPath in indexPaths {
    var newPapers: [Paper] = []
    for (index, paper) in papers.enumerate() {
      if !indexes.contains(index) {
    papers = newPapers
  func indexPathForNewRandomPaper() -> NSIndexPath {
    let index = Int(arc4random_uniform(UInt32(immutablePapers.count)))
    let paperToCopy = immutablePapers[index]
    let newPaper = Paper(copying: paperToCopy)
    papers.sortInPlace { $0.index < $1.index }
    return indexPathForPaper(newPaper)
  func indexPathForPaper(paper: Paper) -> NSIndexPath {
    let section = sections.indexOf(paper.section)!
    var item = 0
    for (index, currentPaper) in papersForSection(section).enumerate() {
      if currentPaper === paper {
        item = index
    return NSIndexPath(forItem: item, inSection: section)
  func movePaperAtIndexPath(indexPath: NSIndexPath, toIndexPath newIndexPath: NSIndexPath) {
    if indexPath == newIndexPath {
    let index = absoluteIndexForIndexPath(indexPath)
    let paper = papers[index]
    paper.section = sections[newIndexPath.section]
    let newIndex = absoluteIndexForIndexPath(newIndexPath)
    papers.insert(paper, atIndex: newIndex)
  func numberOfPapersInSection(index: Int) -> Int {
    let papers = papersForSection(index)
    return papers.count
  func paperForItemAtIndexPath(indexPath: NSIndexPath) -> Paper? {
    if indexPath.section > 0 {
      let papers = papersForSection(indexPath.section)
      return papers[indexPath.item]
    } else {
      return papers[indexPath.item]
  func titleForSectionAtIndexPath(indexPath: NSIndexPath) -> String? {
    if indexPath.section < sections.count {
      return sections[indexPath.section]
    return nil

  // MARK: Private

  private func absoluteIndexForIndexPath(indexPath: NSIndexPath) -> Int {
    var index = 0
    for i in 0..<indexPath.section {
      index += numberOfPapersInSection(i)
    index += indexPath.item
    return index
  private func loadPapersFromDisk() -> [Paper] {
    sections.removeAll(keepCapacity: false)
    if let path = NSBundle.mainBundle().pathForResource("Papers", ofType: "plist") {
      if let dictArray = NSArray(contentsOfFile: path) {
        var papers: [Paper] = []
        for item in dictArray {
          if let dict = item as? NSDictionary {
            let caption = dict["caption"] as! String
            let imageName = dict["imageName"] as! String
            let section = dict["section"] as! String
            let index = dict["index"] as! Int
            let paper = Paper(caption: caption, imageName: imageName, section: section, index: index)
            if !sections.contains(section) {
        return papers
    return []
  private func papersForSection(index: Int) -> [Paper] {
    let section = sections[index]
    let papersInSection = papers.filter { (paper: Paper) -> Bool in
      return paper.section == section
    return papersInSection
1 Like