Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // 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
- > {
- /// Clients are responsible for inserting/removing items in the collection view itself.
- public var sections: SectionCollection
- /// Returns an adapter for this data source that its bridgeable to Objective-C.
- public var bridgedDataSource: UICollectionViewDataSource { return bridgedCollectionViewDataSource }
- private let cellFactory: Factory
- private let bridgedCollectionViewDataSource: BridgeableCollectionViewDataSource! // 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
- bridgedCollectionViewDataSource = BridgeableCollectionViewDataSource(
- 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 {
- // This collection's index is Int, which is a RandomAccessIndexType, so this is O(1).
- return countElements(sections[section])
- }
- private func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
- return cellFactory.cellForItem(sections[indexPath.section][indexPath.row], inCollectionView: collectionView, atIndexPath: indexPath)
- }
- private func numberOfSections() -> Int {
- // This collection's index is Int, which is a RandomAccessIndexType, so this is O(1).
- return countElements(sections)
- }
- }
- /// This separate type is necessary because CollectionViewDataSource itself is necessarily generic, so it can't be bridged to Objective-C.
- @objc private class BridgeableCollectionViewDataSource: 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.
- }
- }
Add Comment
Please, Sign In to add comment