Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import UIKit
- import Foundation
- import ReactiveCocoa
- import Result
- import Dwifft
- /**
- Encapsulates information about collection view nib/cell registration.
- - Nib: UINib.
- - Class: UICollectionViewCell class.
- */
- private enum RegisteredType {
- case Nib(UINib)
- case Class(AnyClass)
- }
- /// CollectionViewBinder is a ReactiveCocoa helper class for simplifying using `UICollectionView`s with ReactiveCocoa.
- /// Using the binder lets the view configuration for collection view cells move to the view and out of the view controller.
- final class CollectionViewBinder<T: Equatable>: NSObject, UICollectionViewDataSource, UICollectionViewDelegate {
- /// `UICollectionViewDelegate` object.
- weak var delegate: UICollectionViewDelegate? {
- get { return self.collectionView?.delegate }
- set { self.collectionView?.delegate = newValue }
- }
- /// `CollectionBinderDataSource` object.
- weak var dataSource: CollectionBinderDataSource? {
- willSet {
- if let _ = newValue {
- reloadData()
- }
- }
- }
- /// `UICollectionView` associated with the binder.
- private(set) weak var collectionView: UICollectionView?
- /// Signal that emits the data
- private var dataSignal: SignalProducer<[[T]], NoError>
- /// Signal that emits the supplementary data
- private var supplementarySignal: SignalProducer<[String: [T]], NoError>?
- /// Mutable data property
- private let data = MutableProperty<[[T]]>([])
- /// Mutable supplementary data property
- private let supplementaryData: MutableProperty<[String: [T]]> = MutableProperty<[String: [T]]>([:])
- // MARK: - Registration Information
- /// All the cells registered with the binder.
- private var cells: [String: RegisteredType] = [:]
- /// All the supplementary views registered with the binder.
- private var supplementaries: [String: (String, RegisteredType)] = [:]
- /// All the decoration views registered with the binder.z
- private var decorations: [String: RegisteredType] = [:]
- /**
- Create a binding helper.
- - parameter collectionView: Collection view object to bind data to.
- - parameter dataSignal: SignalProducer that emits changes to the underlying data.
- - parameter supplementarySignal: SignalProducer that emits changes to the data the represents headers, footers, etc.
- */
- init(collectionView: UICollectionView, dataSignal: SignalProducer<[[T]], NoError>, supplementarySignal: SignalProducer<[String: [T]], NoError>?) {
- self.collectionView = collectionView
- self.dataSignal = dataSignal
- self.supplementarySignal = supplementarySignal
- super.init()
- self.data <~ self.dataSignal
- self.supplementaryData <~ self.supplementarySignal ?? SignalProducer.empty
- self.collectionView?.dataSource = self
- self.data.producer.on(next: { print($0.count) }).on(next: { _ in self.reloadData() }).takeUntil(self.willDeallocSignal()).start()
- }
- // MARK: - UICollectionViewDataSource
- func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
- guard let _ = self.dataSource where !self.cells.isEmpty else {
- return 0
- }
- return self.data.value.count
- }
- func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
- guard let _ = self.dataSource where !self.cells.isEmpty && section < self.data.value.count else {
- return 0
- }
- return self.data.value[section].count
- }
- func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
- guard let dataSource = self.dataSource else {
- return UICollectionViewCell()
- }
- let model = self.data.value[indexPath.section][indexPath.item]
- if let reuseIdentifier = dataSource.collectionView(collectionView, reuseIdentifierForItemAtIndexPath: indexPath) {
- let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
- if cell is ReactiveView {
- (cell as! ReactiveView).bindViewModel(model)
- }
- return cell
- }
- return UICollectionViewCell()
- }
- func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
- if let model = self.supplementaryData.value[kind]?[indexPath.section],
- reuseIdentifier = self.dataSource?.collectionView(collectionView, reuseIdentifierForSupplementaryViewOfKind: kind, atIndexPath: indexPath) {
- let view = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: reuseIdentifier, forIndexPath: indexPath)
- if view is ReactiveView {
- (view as! ReactiveView).bindViewModel(model)
- }
- return view
- }
- return UICollectionReusableView()
- }
- }
- // MARK: - Registering Views
- extension CollectionViewBinder {
- /**
- Register a nib for a cell reuse identifier.
- - parameter nib: Nib object.
- - parameter identifier: Reuse identifier to register the specified nib with.
- */
- func registerNib(nib: UINib, forCellReuseIdentifier identifier: String) {
- self.cells[identifier] = .Nib(nib)
- self.collectionView?.registerNib(nib, forCellWithReuseIdentifier: identifier)
- }
- /**
- Register a class for a cell reuse identifier.
- - parameter aClass: Class object.
- - parameter identifier: Reuse identifier to register the specified class with.
- */
- func registerClass(aClass: AnyClass, forCellReuseIdentifier identifier: String) {
- self.cells[identifier] = .Class(aClass)
- self.collectionView?.registerClass(aClass, forCellWithReuseIdentifier: identifier)
- }
- /**
- Register a nib for a supplementary reuse identifier.
- - parameter nib: Nib object.
- - parameter kind: Supplementary element kind.
- - parameter identifier: Reuse identifier to register the specified nib with.
- */
- func registerNib(nib: UINib, forSupplementaryViewOfKind kind: String, withReuseIdentifier identifier: String) {
- self.supplementaries[kind] = (identifier, .Nib(nib))
- self.collectionView?.registerNib(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: identifier)
- }
- /**
- Register a class for a supplementary reuse identifier.
- - parameter aClass: Class object.
- - parameter kind: Supplementary element kind.
- - parameter identifier: Reuse identifier to register the specified class with.
- */
- func registerClass(aClass: AnyClass, forSupplementaryViewOfKind kind: String, withReuseIdentifier identifier: String) {
- self.supplementaries[kind] = (identifier, .Class(aClass))
- self.collectionView?.registerClass(aClass, forSupplementaryViewOfKind: kind, withReuseIdentifier: identifier)
- }
- /**
- Register a nib for a decoration kind.
- - parameter nib: Nib object.
- - parameter elementKind: Decoration identifier.
- */
- func registerNib(nib: UINib, forDecorationViewOfKind elementKind: String) {
- self.decorations[elementKind] = .Nib(nib)
- self.collectionView?.collectionViewLayout.registerNib(nib, forDecorationViewOfKind: elementKind)
- }
- /**
- Register a class for a decoration kind.
- - parameter aClass: Class object.
- - parameter elementKind: Decoration identifier.
- */
- func registerClass(aClass: AnyClass, forDecorationViewOfKind elementKind: String) {
- self.decorations[elementKind] = .Class(aClass)
- self.collectionView?.collectionViewLayout.registerClass(aClass, forDecorationViewOfKind: elementKind)
- }
- }
- // MARK: - Reloading
- extension CollectionViewBinder {
- /**
- Reload the binder.
- */
- func reloadData() {
- dispatch_async(dispatch_get_main_queue(), { [weak self] in
- self?.collectionView?.reloadData()
- })
- }
- /**
- Reload the specified sections.
- - parameter indexes: Index set of sections to reload.
- */
- func reloadSections(indexes: NSIndexSet) {
- dispatch_async(dispatch_get_main_queue(), { [weak self] in
- self?.collectionView?.reloadSections(indexes)
- })
- }
- /**
- Reload all the items at the specified index paths.
- - parameter indexPaths: List of index paths to reload.
- */
- func reloadItemsAtIndexPaths(indexPaths: [NSIndexPath]) {
- dispatch_async(dispatch_get_main_queue(), { [weak self] in
- self?.collectionView?.reloadItemsAtIndexPaths(indexPaths)
- })
- }
- /**
- Reload the input views.
- */
- func reloadInputViews() {
- dispatch_async(dispatch_get_main_queue(), { [weak self] in
- self?.collectionView?.reloadInputViews()
- })
- }
- }
Add Comment
Please, Sign In to add comment