Guest User

Untitled

a guest
Jul 30th, 2016
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.08 KB | None | 0 0
  1. //
  2. // CollectionViewDataSource.swift
  3. // Khan Academy
  4. //
  5. // Created by Andy Matuschak on 10/14/14.
  6. // Copyright (c) 2014 Khan Academy. All rights reserved.
  7. //
  8.  
  9. import UIKit
  10.  
  11. /// A type which can produce and configure a cell for a given item.
  12. public protocol CollectionViewCellFactoryType {
  13. typealias Item
  14. typealias Cell: UICollectionViewCell
  15. func cellForItem(item: Item, inCollectionView collectionView: UICollectionView, atIndexPath indexPath: NSIndexPath) -> Cell
  16. }
  17.  
  18. /// A concrete cell factory which makes use of UICollectionView's built-in cell reuse queue.
  19. public struct RegisteredCollectionViewCellFactory<Cell: UICollectionViewCell, Item>: CollectionViewCellFactoryType {
  20. private let reuseIdentifier: String
  21. private let cellConfigurator: (Cell, Item) -> ()
  22.  
  23. /// You must register Cell.Type with your collection view for `reuseIdentifier`.
  24. public init(reuseIdentifier: String, cellConfigurator: (Cell, Item) -> ()) {
  25. self.reuseIdentifier = reuseIdentifier
  26. self.cellConfigurator = cellConfigurator
  27. }
  28.  
  29. public func cellForItem(item: Item, inCollectionView collectionView: UICollectionView, atIndexPath indexPath: NSIndexPath) -> Cell {
  30. // Will abort if you haven't already registered this reuse identifier for Cell.Type.
  31. let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as Cell
  32. cellConfigurator(cell, item)
  33. return cell
  34. }
  35. }
  36.  
  37. /// 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.
  38. /// Use `bridgedDataSource` to get a UICollectionViewDataSource instance.
  39. public class CollectionViewDataSource<
  40. SectionCollection: CollectionType,
  41. Factory: CollectionViewCellFactoryType,
  42. Item
  43. where
  44. SectionCollection.Index == Int,
  45. SectionCollection.Generator.Element: CollectionType,
  46. SectionCollection.Generator.Element.Generator.Element == Item,
  47. SectionCollection.Generator.Element.Index == Int,
  48. Factory.Item == Item
  49. > {
  50.  
  51. /// Clients are responsible for inserting/removing items in the collection view itself.
  52. public var sections: SectionCollection
  53.  
  54. /// Returns an adapter for this data source that its bridgeable to Objective-C.
  55. public var bridgedDataSource: UICollectionViewDataSource { return bridgedCollectionViewDataSource }
  56.  
  57. private let cellFactory: Factory
  58. private let bridgedCollectionViewDataSource: BridgeableCollectionViewDataSource! // The bridge is initialized with a reference to self, so Swift thinks (correctly) that this could conceivably be used uninitialized.
  59.  
  60. public init(sections: SectionCollection, cellFactory: Factory) {
  61. self.sections = sections
  62. self.cellFactory = cellFactory
  63. bridgedCollectionViewDataSource = BridgeableCollectionViewDataSource(
  64. numberOfItemsInSectionHandler: { [weak self] in self?.numberOfItemsInSection($0) ?? 0 },
  65. cellForItemAtIndexPathHandler: { [weak self] in self?.collectionView($0, cellForItemAtIndexPath: $1) },
  66. numberOfSectionsHandler: { [weak self] in self?.numberOfSections() ?? 0 }
  67. )
  68. }
  69.  
  70. private func numberOfItemsInSection(section: Int) -> Int {
  71. // This collection's index is Int, which is a RandomAccessIndexType, so this is O(1).
  72. return countElements(sections[section])
  73. }
  74.  
  75. private func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  76. return cellFactory.cellForItem(sections[indexPath.section][indexPath.row], inCollectionView: collectionView, atIndexPath: indexPath)
  77. }
  78.  
  79. private func numberOfSections() -> Int {
  80. // This collection's index is Int, which is a RandomAccessIndexType, so this is O(1).
  81. return countElements(sections)
  82. }
  83.  
  84. }
  85.  
  86.  
  87. /// This separate type is necessary because CollectionViewDataSource itself is necessarily generic, so it can't be bridged to Objective-C.
  88. @objc private class BridgeableCollectionViewDataSource: NSObject, UICollectionViewDataSource {
  89.  
  90. private let numberOfItemsInSectionHandler: Int -> Int
  91. private let cellForItemAtIndexPathHandler: (UICollectionView, NSIndexPath) -> UICollectionViewCell?
  92. private let numberOfSectionsHandler: () -> Int
  93.  
  94. init(numberOfItemsInSectionHandler: Int -> Int, cellForItemAtIndexPathHandler: (UICollectionView, NSIndexPath) -> UICollectionViewCell?, numberOfSectionsHandler: () -> Int) {
  95. self.numberOfItemsInSectionHandler = numberOfItemsInSectionHandler
  96. self.cellForItemAtIndexPathHandler = cellForItemAtIndexPathHandler
  97. self.numberOfSectionsHandler = numberOfSectionsHandler
  98. }
  99.  
  100. func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
  101. return numberOfSectionsHandler()
  102. }
  103.  
  104. func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  105. return numberOfItemsInSectionHandler(section)
  106. }
  107.  
  108. // The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
  109. func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  110. return cellForItemAtIndexPathHandler(collectionView, indexPath)! // Better not have the data source bridge outlive the data source itself.
  111. }
  112.  
  113. }
Add Comment
Please, Sign In to add comment