Created
October 14, 2014 23:57
-
-
Save ka-interview/a6478004c6cee552f225 to your computer and use it in GitHub Desktop.
Sketch of type safe, non-AnyObject-supporting data source
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public protocol CountableCollectionType: CollectionType { | |
var count: Int { get } | |
} | |
extension Array: CountableCollectionType {} | |
public protocol CollectionViewCellFactoryType { | |
typealias Item | |
typealias Cell: UICollectionViewCell | |
func cellForItem(item: Item, inCollectionView collectionView: UICollectionView, atIndexPath indexPath: NSIndexPath) -> Cell | |
} | |
public struct RegisteredCollectionViewCellFactory<Cell: UICollectionViewCell, Item>: CollectionViewCellFactoryType { | |
private let reuseIdentifier: String | |
private let cellConfigurator: (Cell, Item) -> () | |
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 a cell of type Cell with the collection view under reuseIdentifier. | |
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as Cell | |
cellConfigurator(cell, item) | |
return cell | |
} | |
} | |
public class StaticCollectionViewDataSource< | |
SectionCollection: CountableCollectionType, | |
Factory: CollectionViewCellFactoryType, | |
ItemType | |
where | |
SectionCollection.Index == Int, | |
SectionCollection.Generator.Element: CountableCollectionType, | |
SectionCollection.Generator.Element.Generator.Element == ItemType, | |
SectionCollection.Generator.Element.Index == Int, | |
Factory.Item == ItemType> { | |
public var sections: SectionCollection | |
private let cellFactory: Factory | |
private let staticCollectionViewDataSourceBridge: StaticCollectionViewDataSourceBridge! // The bridge is initialized with a reference to self, so Swift thinks (correctly) that this could conceivably be used uninitialized. | |
public init(sections: SectionCollection, cellFactory: Factory) { | |
self.sections = sections | |
self.cellFactory = cellFactory | |
staticCollectionViewDataSourceBridge = StaticCollectionViewDataSourceBridge( | |
numberOfItemsInSectionHandler: { [weak self] in self?.numberOfItemsInSection($0) ?? 0 }, | |
cellForItemAtIndexPathHandler: { [weak self] in self?.collectionView($0, cellForItemAtIndexPath: $1) }, | |
numberOfSectionsHandler: { [weak self] in self?.numberOfSections() ?? 0 }) | |
} | |
private func numberOfItemsInSection(section: Int) -> Int { | |
return sections[section].count | |
} | |
private func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { | |
let section = sections[indexPath.section] | |
let item: ItemType = section[indexPath.row] | |
return cellFactory.cellForItem(item, inCollectionView: collectionView, atIndexPath: indexPath) | |
} | |
private func numberOfSections() -> Int { | |
return sections.count | |
} | |
public var bridgedDataSource: UICollectionViewDataSource { return staticCollectionViewDataSourceBridge } | |
} | |
@objc private class StaticCollectionViewDataSourceBridge: NSObject, UICollectionViewDataSource { | |
private let numberOfItemsInSectionHandler: Int -> Int | |
private let cellForItemAtIndexPathHandler: (UICollectionView, NSIndexPath) -> UICollectionViewCell? | |
private let numberOfSectionsHandler: () -> Int | |
init(numberOfItemsInSectionHandler: Int -> Int, cellForItemAtIndexPathHandler: (UICollectionView, NSIndexPath) -> UICollectionViewCell?, numberOfSectionsHandler: () -> Int) { | |
self.numberOfItemsInSectionHandler = numberOfItemsInSectionHandler | |
self.cellForItemAtIndexPathHandler = cellForItemAtIndexPathHandler | |
self.numberOfSectionsHandler = numberOfSectionsHandler | |
} | |
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { | |
return numberOfSectionsHandler() | |
} | |
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { | |
return numberOfItemsInSectionHandler(section) | |
} | |
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath: | |
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { | |
return cellForItemAtIndexPathHandler(collectionView, indexPath)! // Better not have the data source bridge outlive the data source itself. | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment