Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save neilpa/b9491c8ffbb454ed2af2 to your computer and use it in GitHub Desktop.
Save neilpa/b9491c8ffbb454ed2af2 to your computer and use it in GitHub Desktop.
Type-safe value-oriented collection view data source
//
// CollectionViewDataSource.swift
// Khan Academy
//
// Created by Andy Matuschak on 10/14/14.
// Copyright (c) 2014 Khan Academy. All rights reserved.
//
import UIKit
/// A type which can produce and configure a cell for a given item.
public protocol CollectionViewCellFactoryType {
typealias Item
typealias Cell: UICollectionViewCell
func cellForItem(item: Item, inCollectionView collectionView: UICollectionView, atIndexPath indexPath: NSIndexPath) -> Cell
}
/// A concrete cell factory which makes use of UICollectionView's built-in cell reuse queue.
public struct RegisteredCollectionViewCellFactory<Cell: UICollectionViewCell, Item>: CollectionViewCellFactoryType {
private let reuseIdentifier: String
private let cellConfigurator: (Cell, Item) -> ()
/// You must register Cell.Type with your collection view for `reuseIdentifier`.
public init(reuseIdentifier: String, cellConfigurator: (Cell, Item) -> ()) {
self.reuseIdentifier = reuseIdentifier
self.cellConfigurator = cellConfigurator
}
public func cellForItem(item: Item, inCollectionView collectionView: UICollectionView, atIndexPath indexPath: NSIndexPath) -> Cell {
// Will abort if you haven't already registered this reuse identifier for Cell.Type.
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! Cell
cellConfigurator(cell, item)
return cell
}
}
/// A type-safe collection view data source. Clients can specify its sections and their contents via any CollectionType. Configuration of the cells is delegated to an external factory type.
/// Use `bridgedDataSource` to get a UICollectionViewDataSource instance.
public class CollectionViewDataSource<
SectionCollection: CollectionType,
Factory: CollectionViewCellFactoryType,
Item
where
SectionCollection.Index == Int,
SectionCollection.Generator.Element: CollectionType,
SectionCollection.Generator.Element.Generator.Element == Item,
SectionCollection.Generator.Element.Index == Int,
Factory.Item == Item
>: NSObject, UICollectionViewDataSource {
/// Clients are responsible for inserting/removing items in the collection view itself.
public var sections: SectionCollection
private let cellFactory: Factory
public init(sections: SectionCollection, cellFactory: Factory) {
self.sections = sections
self.cellFactory = cellFactory
super.init()
}
final public func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return sections.count
}
final public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return sections[section].count
}
final public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
return cellFactory.cellForItem(sections[indexPath.section][indexPath.row], inCollectionView: collectionView, atIndexPath: indexPath)
}
}
// ...
let cellFactory = RegisteredCollectionViewCellFactory(reuseIdentifier: "Topic") { (cell: TopicCatalogCell, topic: Topic) in
cell.topic = topic
}
dataSource = CollectionViewDataSource(sections: [topics], cellFactory: cellFactory)
topicCollectionView = UICollectionView(frame: CGRect(), collectionViewLayout: topicCollectionViewLayout)
topicCollectionView.dataSource = dataSource
@neilpa
Copy link
Author

neilpa commented Oct 28, 2015

Updated for Swift 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment