From d91e4bfe9dd53ddbc7005f201ba7c52ed7851bae Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 8 Oct 2017 15:46:39 +0200 Subject: [PATCH] Adapts collection and table view to use Swift 4.0 capabilities. --- ..._CustomizationUsingTableViewDelegate.swift | 27 ++- ...Example2_RandomizedSectionsAnimation.swift | 79 ++++--- Example/Example3_TableViewEditing.swift | 50 ++--- ...xample4_DifferentSectionAndItemTypes.swift | 62 +++--- RxDataSources.xcodeproj/project.pbxproj | 4 + .../AnimationConfiguration.swift | 36 +-- .../CollectionViewSectionedDataSource.swift | 119 +++------- Sources/RxDataSources/Deprecated.swift | 19 ++ ...ctionViewSectionedAnimatedDataSource.swift | 40 ++-- ...lectionViewSectionedReloadDataSource.swift | 4 - ...TableViewSectionedAnimatedDataSource.swift | 50 ++++- ...RxTableViewSectionedReloadDataSource.swift | 4 - .../TableViewSectionedDataSource.swift | 209 ++++++------------ 13 files changed, 328 insertions(+), 375 deletions(-) create mode 100644 Sources/RxDataSources/Deprecated.swift diff --git a/Example/Example1_CustomizationUsingTableViewDelegate.swift b/Example/Example1_CustomizationUsingTableViewDelegate.swift index a9b611c6..110bd9aa 100644 --- a/Example/Example1_CustomizationUsingTableViewDelegate.swift +++ b/Example/Example1_CustomizationUsingTableViewDelegate.swift @@ -42,18 +42,19 @@ class CustomizationUsingTableViewDelegate : UIViewController { tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") - let dataSource = RxTableViewSectionedAnimatedDataSource() + let dataSource = RxTableViewSectionedAnimatedDataSource( + configureCell: { ds, tv, ip, item in + let cell = tv.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell") + cell.textLabel?.text = "Item \(item)" + + return cell + }, + titleForHeaderInSection: { ds, index in + return ds.sectionModels[index].header + } + ) - dataSource.configureCell = { ds, tv, ip, item in - let cell = tv.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell") - cell.textLabel?.text = "Item \(item)" - - return cell - } - - dataSource.titleForHeaderInSection = { ds, index in - return ds.sectionModels[index].header - } + self.dataSource = dataSource let sections = [ MySection(header: "First section", items: [ @@ -72,8 +73,6 @@ class CustomizationUsingTableViewDelegate : UIViewController { tableView.rx.setDelegate(self) .addDisposableTo(disposeBag) - - self.dataSource = dataSource } } @@ -88,6 +87,6 @@ extension CustomizationUsingTableViewDelegate : UITableViewDelegate { return 0.0 } - return CGFloat(40 + item) + return CGFloat(40 + item * 10) } } diff --git a/Example/Example2_RandomizedSectionsAnimation.swift b/Example/Example2_RandomizedSectionsAnimation.swift index e84cef73..0c47f77d 100644 --- a/Example/Example2_RandomizedSectionsAnimation.swift +++ b/Example/Example2_RandomizedSectionsAnimation.swift @@ -44,11 +44,16 @@ class ViewController: UIViewController { return a.sections } .shareReplay(1) - let tvAnimatedDataSource = RxTableViewSectionedAnimatedDataSource() - let reloadDataSource = RxTableViewSectionedReloadDataSource() - skinTableViewDataSource(tvAnimatedDataSource) - skinTableViewDataSource(reloadDataSource) + let (configureCell, titleForSection) = ViewController.tableViewDataSourceUI() + let tvAnimatedDataSource = RxTableViewSectionedAnimatedDataSource( + configureCell: configureCell, + titleForHeaderInSection: titleForSection + ) + let reloadDataSource = RxTableViewSectionedReloadDataSource( + configureCell: configureCell, + titleForHeaderInSection: titleForSection + ) randomSections .bind(to: animatedTableView.rx.items(dataSource: tvAnimatedDataSource)) @@ -58,8 +63,11 @@ class ViewController: UIViewController { .bind(to: tableView.rx.items(dataSource: reloadDataSource)) .addDisposableTo(disposeBag) - let cvAnimatedDataSource = RxCollectionViewSectionedAnimatedDataSource() - skinCollectionViewDataSource(cvAnimatedDataSource) + let (configureCollectionViewCell, configureSupplementaryView) = ViewController.collectionViewDataSourceUI() + let cvAnimatedDataSource = RxCollectionViewSectionedAnimatedDataSource( + configureCell: configureCollectionViewCell, + configureSupplementaryView: configureSupplementaryView + ) randomSections .bind(to: animatedCollectionView.rx.items(dataSource: cvAnimatedDataSource)) @@ -83,36 +91,39 @@ class ViewController: UIViewController { // MARK: Skinning extension ViewController { - func skinTableViewDataSource(_ dataSource: TableViewSectionedDataSource) { - dataSource.configureCell = { (_, tv, ip, i) in - let cell = tv.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style:.default, reuseIdentifier: "Cell") - - cell.textLabel!.text = "\(i)" - - return cell - } - - dataSource.titleForHeaderInSection = { (ds, section) -> String? in - return ds[section].header - } + static func tableViewDataSourceUI() -> ( + TableViewSectionedDataSource.ConfigureCell, + TableViewSectionedDataSource.TitleForHeaderInSection + ) { + return ( + { (_, tv, ip, i) in + let cell = tv.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style:.default, reuseIdentifier: "Cell") + cell.textLabel!.text = "\(i)" + return cell + }, + { (ds, section) -> String? in + return ds[section].header + } + ) } - func skinCollectionViewDataSource(_ dataSource: CollectionViewSectionedDataSource) { - dataSource.configureCell = { (_, cv, ip, i) in - let cell = cv.dequeueReusableCell(withReuseIdentifier: "Cell", for: ip) as! NumberCell - - cell.value!.text = "\(i)" - - return cell - } - - dataSource.supplementaryViewFactory = { (ds ,cv, kind, ip) in - let section = cv.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Section", for: ip) as! NumberSectionView - - section.value!.text = "\(ds[ip.section].header)" - - return section - } + static func collectionViewDataSourceUI() -> ( + CollectionViewSectionedDataSource.ConfigureCell, + CollectionViewSectionedDataSource.ConfigureSupplementaryView + ) { + return ( + { (_, cv, ip, i) in + let cell = cv.dequeueReusableCell(withReuseIdentifier: "Cell", for: ip) as! NumberCell + cell.value!.text = "\(i)" + return cell + + }, + { (ds ,cv, kind, ip) in + let section = cv.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Section", for: ip) as! NumberSectionView + section.value!.text = "\(ds[ip.section].header)" + return section + } + ) } // MARK: Initial value diff --git a/Example/Example3_TableViewEditing.swift b/Example/Example3_TableViewEditing.swift index dcd6d394..5a866e42 100644 --- a/Example/Example3_TableViewEditing.swift +++ b/Example/Example3_TableViewEditing.swift @@ -22,7 +22,8 @@ class EditingExampleViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - let dataSource = RxTableViewSectionedAnimatedDataSource() + let dataSource = EditingExampleViewController.dataSource() + let sections: [NumberSection] = [NumberSection(header: "Section 1", numbers: [], updated: Date()), NumberSection(header: "Section 2", numbers: [], updated: Date()), NumberSection(header: "Section 3", numbers: [], updated: Date())] @@ -39,7 +40,6 @@ class EditingExampleViewController: UIViewController { let movedCommand = tableView.rx.itemMoved .map(TableViewEditingCommand.MoveItem) - skinTableViewDataSource(dataSource: dataSource) Observable.of(addCommand, deleteCommand, movedCommand) .merge() .scan(initialState) { (state: SectionedTableViewState, command: TableViewEditingCommand) -> SectionedTableViewState in @@ -58,31 +58,29 @@ class EditingExampleViewController: UIViewController { super.viewDidAppear(animated) tableView.setEditing(true, animated: true) } - - func skinTableViewDataSource(dataSource: RxTableViewSectionedAnimatedDataSource) { - - dataSource.animationConfiguration = AnimationConfiguration(insertAnimation: .top, +} + +extension EditingExampleViewController { + static func dataSource() -> RxTableViewSectionedAnimatedDataSource { + return RxTableViewSectionedAnimatedDataSource( + animationConfiguration: AnimationConfiguration(insertAnimation: .top, reloadAnimation: .fade, - deleteAnimation: .left) - - dataSource.configureCell = { (dataSource, table, idxPath, item) in - let cell = table.dequeueReusableCell(withIdentifier: "Cell", for: idxPath) - - cell.textLabel?.text = "\(item)" - - return cell - } - - dataSource.titleForHeaderInSection = { (ds, section) -> String? in - return ds[section].header - } - - dataSource.canEditRowAtIndexPath = { _, _ in - return true - } - dataSource.canMoveRowAtIndexPath = { _, _ in - return true - } + deleteAnimation: .left), + configureCell: { (dataSource, table, idxPath, item) in + let cell = table.dequeueReusableCell(withIdentifier: "Cell", for: idxPath) + cell.textLabel?.text = "\(item)" + return cell + }, + titleForHeaderInSection: { (ds, section) -> String? in + return ds[section].header + }, + canEditRowAtIndexPath: { _, _ in + return true + }, + canMoveRowAtIndexPath: { _, _ in + return true + } + ) } } diff --git a/Example/Example4_DifferentSectionAndItemTypes.swift b/Example/Example4_DifferentSectionAndItemTypes.swift index c5bbe16b..dc710aef 100644 --- a/Example/Example4_DifferentSectionAndItemTypes.swift +++ b/Example/Example4_DifferentSectionAndItemTypes.swift @@ -29,43 +29,43 @@ class MultipleSectionModelViewController: UIViewController { items: [.StepperSectionItem(title: "1")]) ] - let dataSource = RxTableViewSectionedReloadDataSource() - - skinTableViewDataSource(dataSource) + let dataSource = MultipleSectionModelViewController.dataSource() Observable.just(sections) .bind(to: tableView.rx.items(dataSource: dataSource)) .addDisposableTo(disposeBag) } - - func skinTableViewDataSource(_ dataSource: RxTableViewSectionedReloadDataSource) { - dataSource.configureCell = { (dataSource, table, idxPath, _) in - switch dataSource[idxPath] { - case let .ImageSectionItem(image, title): - let cell: ImageTitleTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath) - cell.titleLabel.text = title - cell.cellImageView.image = image - - return cell - case let .StepperSectionItem(title): - let cell: TitleSteperTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath) - cell.titleLabel.text = title - - return cell - case let .ToggleableSectionItem(title, enabled): - let cell: TitleSwitchTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath) - cell.switchControl.isOn = enabled - cell.titleLabel.text = title - - return cell - } - } +} - dataSource.titleForHeaderInSection = { dataSource, index in - let section = dataSource[index] - - return section.title - } +extension MultipleSectionModelViewController { + static func dataSource() -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( + configureCell: { (dataSource, table, idxPath, _) in + switch dataSource[idxPath] { + case let .ImageSectionItem(image, title): + let cell: ImageTitleTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath) + cell.titleLabel.text = title + cell.cellImageView.image = image + + return cell + case let .StepperSectionItem(title): + let cell: TitleSteperTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath) + cell.titleLabel.text = title + + return cell + case let .ToggleableSectionItem(title, enabled): + let cell: TitleSwitchTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath) + cell.switchControl.isOn = enabled + cell.titleLabel.text = title + + return cell + } + }, + titleForHeaderInSection: { dataSource, index in + let section = dataSource[index] + return section.title + } + ) } } diff --git a/RxDataSources.xcodeproj/project.pbxproj b/RxDataSources.xcodeproj/project.pbxproj index d01278ae..1aa332da 100644 --- a/RxDataSources.xcodeproj/project.pbxproj +++ b/RxDataSources.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ C82C3C961F3B939100309AE8 /* SectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82C3C701F3B938C00309AE8 /* SectionModel.swift */; }; C82C3C971F3B939100309AE8 /* SectionModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82C3C711F3B938C00309AE8 /* SectionModelType.swift */; }; C82C3C991F3B939100309AE8 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82C3C731F3B938C00309AE8 /* Utilities.swift */; }; + C833338D1F8A5FAC00D46EAE /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C833338C1F8A5FAC00D46EAE /* Deprecated.swift */; }; C87C34991F363B1400DB85FE /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C87C34321F36346A00DB85FE /* RxSwift.framework */; }; C87C349A1F363B1400DB85FE /* RxSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C87C34321F36346A00DB85FE /* RxSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C87C349D1F363B1400DB85FE /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C87C343A1F36346A00DB85FE /* RxCocoa.framework */; }; @@ -365,6 +366,7 @@ C82C3C701F3B938C00309AE8 /* SectionModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionModel.swift; sourceTree = ""; }; C82C3C711F3B938C00309AE8 /* SectionModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionModelType.swift; sourceTree = ""; }; C82C3C731F3B938C00309AE8 /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; + C833338C1F8A5FAC00D46EAE /* Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deprecated.swift; sourceTree = ""; }; C861C0F01E153FC400BEDC46 /* RxDataSources.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = RxDataSources.podspec; sourceTree = ""; }; C87C34191F36346A00DB85FE /* Rx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Rx.xcodeproj; path = RxSwift/Rx.xcodeproj; sourceTree = ""; }; C87DF3431D0219A7006308C5 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -663,6 +665,7 @@ C8BBFBD41F3B8F8D00A225F7 /* RxTableViewSectionedReloadDataSource.swift */, C8BBFBD51F3B8F8D00A225F7 /* TableViewSectionedDataSource.swift */, C8BBFBD61F3B8F8D00A225F7 /* UI+SectionedViewType.swift */, + C833338C1F8A5FAC00D46EAE /* Deprecated.swift */, ); path = RxDataSources; sourceTree = ""; @@ -1132,6 +1135,7 @@ C8BBFBE01F3B8F8D00A225F7 /* TableViewSectionedDataSource.swift in Sources */, C8BBFBE11F3B8F8D00A225F7 /* UI+SectionedViewType.swift in Sources */, C8BBFBDB1F3B8F8D00A225F7 /* RxCollectionViewSectionedReloadDataSource.swift in Sources */, + C833338D1F8A5FAC00D46EAE /* Deprecated.swift in Sources */, C81FBF631F3B9DC00094061E /* IntegerType+IdentifiableType.swift in Sources */, C8BBFBDD1F3B8F8D00A225F7 /* RxPickerViewAdapter.swift in Sources */, ); diff --git a/Sources/RxDataSources/AnimationConfiguration.swift b/Sources/RxDataSources/AnimationConfiguration.swift index 9414aa03..3d08a61f 100644 --- a/Sources/RxDataSources/AnimationConfiguration.swift +++ b/Sources/RxDataSources/AnimationConfiguration.swift @@ -7,23 +7,23 @@ // #if os(iOS) || os(tvOS) -import Foundation -import UIKit + import Foundation + import UIKit -/** - Exposes custom animation styles for insertion, deletion and reloading behavior. -*/ -public struct AnimationConfiguration { - public let insertAnimation: UITableViewRowAnimation - public let reloadAnimation: UITableViewRowAnimation - public let deleteAnimation: UITableViewRowAnimation - - public init(insertAnimation: UITableViewRowAnimation = .automatic, - reloadAnimation: UITableViewRowAnimation = .automatic, - deleteAnimation: UITableViewRowAnimation = .automatic) { - self.insertAnimation = insertAnimation - self.reloadAnimation = reloadAnimation - self.deleteAnimation = deleteAnimation - } -} + /** + Exposes custom animation styles for insertion, deletion and reloading behavior. + */ + public struct AnimationConfiguration { + public let insertAnimation: UITableViewRowAnimation + public let reloadAnimation: UITableViewRowAnimation + public let deleteAnimation: UITableViewRowAnimation + + public init(insertAnimation: UITableViewRowAnimation = .automatic, + reloadAnimation: UITableViewRowAnimation = .automatic, + deleteAnimation: UITableViewRowAnimation = .automatic) { + self.insertAnimation = insertAnimation + self.reloadAnimation = reloadAnimation + self.deleteAnimation = deleteAnimation + } + } #endif diff --git a/Sources/RxDataSources/CollectionViewSectionedDataSource.swift b/Sources/RxDataSources/CollectionViewSectionedDataSource.swift index 80cebd6e..7ec3a9e3 100644 --- a/Sources/RxDataSources/CollectionViewSectionedDataSource.swift +++ b/Sources/RxDataSources/CollectionViewSectionedDataSource.swift @@ -14,66 +14,29 @@ import RxCocoa #endif import Differentiator -open class _CollectionViewSectionedDataSource - : NSObject - , UICollectionViewDataSource { - - open func _rx_numberOfSections(in collectionView: UICollectionView) -> Int { - return 0 - } - - open func numberOfSections(in collectionView: UICollectionView) -> Int { - return _rx_numberOfSections(in: collectionView) - } - - open func _rx_collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return 0 - } - - open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return _rx_collectionView(collectionView, numberOfItemsInSection: section) - } - - open func _rx_collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - return (nil as UICollectionViewCell?)! - } - - open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - return _rx_collectionView(collectionView, cellForItemAt: indexPath) - } - - open func _rx_collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: IndexPath) -> UICollectionReusableView { - return (nil as UICollectionReusableView?)! - } - - open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - return _rx_collectionView(collectionView, viewForSupplementaryElementOfKind: kind, atIndexPath: indexPath) - } - - open func _rx_collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { - return true - } - - public func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { - return _rx_collectionView(collectionView, canMoveItemAt: indexPath) - } - - open func _rx_collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - - } - public func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - _rx_collectionView(collectionView, moveItemAt: sourceIndexPath, to: destinationIndexPath) - } - -} - open class CollectionViewSectionedDataSource - : _CollectionViewSectionedDataSource + : NSObject + , UICollectionViewDataSource , SectionedViewDataSourceType { public typealias I = S.Item public typealias Section = S - public typealias CellFactory = (CollectionViewSectionedDataSource, UICollectionView, IndexPath, I) -> UICollectionViewCell - public typealias SupplementaryViewFactory = (CollectionViewSectionedDataSource, UICollectionView, String, IndexPath) -> UICollectionReusableView + public typealias ConfigureCell = (CollectionViewSectionedDataSource, UICollectionView, IndexPath, I) -> UICollectionViewCell + public typealias ConfigureSupplementaryView = (CollectionViewSectionedDataSource, UICollectionView, String, IndexPath) -> UICollectionReusableView + public typealias MoveItem = (CollectionViewSectionedDataSource, _ sourceIndexPath:IndexPath, _ destinationIndexPath:IndexPath) -> Void + public typealias CanMoveItemAtIndexPath = (CollectionViewSectionedDataSource, IndexPath) -> Bool + + + public init( + configureCell: @escaping ConfigureCell, + configureSupplementaryView: @escaping ConfigureSupplementaryView, + moveItem: @escaping MoveItem = { _, _, _ in () }, + canMoveItemAtIndexPath: @escaping CanMoveItemAtIndexPath = { _, _ in false } + ) { + self.configureCell = configureCell + self.configureSupplementaryView = configureSupplementaryView + self.moveItem = moveItem + self.canMoveItemAtIndexPath = canMoveItemAtIndexPath + } #if DEBUG // If data source has already been bound, then mutating it @@ -125,7 +88,7 @@ open class CollectionViewSectionedDataSource self._sectionModels = sections.map { SectionModelSnapshot(model: $0, items: $0.items) } } - open var configureCell: CellFactory! = nil { + open var configureCell: ConfigureCell { didSet { #if DEBUG ensureNotMutatedAfterBinding() @@ -133,7 +96,7 @@ open class CollectionViewSectionedDataSource } } - open var supplementaryViewFactory: SupplementaryViewFactory { + open var configureSupplementaryView: ConfigureSupplementaryView { didSet { #if DEBUG ensureNotMutatedAfterBinding() @@ -141,7 +104,7 @@ open class CollectionViewSectionedDataSource } } - open var moveItem: ((CollectionViewSectionedDataSource, _ sourceIndexPath:IndexPath, _ destinationIndexPath:IndexPath) -> Void)? { + open var moveItem: MoveItem { didSet { #if DEBUG ensureNotMutatedAfterBinding() @@ -155,56 +118,38 @@ open class CollectionViewSectionedDataSource #endif } } - - public override init() { - self.configureCell = {_, _, _, _ in return (nil as UICollectionViewCell?)! } - self.supplementaryViewFactory = {_, _, _, _ in (nil as UICollectionReusableView?)! } - - super.init() - - self.configureCell = { [weak self] _, _, _, _ in - precondition(false, "There is a minor problem. `cellFactory` property on \(self!) was not set. Please set it manually, or use one of the `rx_bindTo` methods.") - - return (nil as UICollectionViewCell!)! - } - - self.supplementaryViewFactory = { [weak self] _, _, _, _ in - precondition(false, "There is a minor problem. `supplementaryViewFactory` property on \(self!) was not set.") - return (nil as UICollectionReusableView?)! - } - } - + // UICollectionViewDataSource - open override func _rx_numberOfSections(in collectionView: UICollectionView) -> Int { + open func numberOfSections(in collectionView: UICollectionView) -> Int { return _sectionModels.count } - open override func _rx_collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return _sectionModels[section].items.count } - open override func _rx_collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { precondition(indexPath.item < _sectionModels[indexPath.section].items.count) return configureCell(self, collectionView, indexPath, self[indexPath]) } - open override func _rx_collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: IndexPath) -> UICollectionReusableView { - return supplementaryViewFactory(self, collectionView, kind, indexPath) + open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + return configureSupplementaryView(self, collectionView, kind, indexPath) } - open override func _rx_collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { + open func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { guard let canMoveItem = canMoveItemAtIndexPath?(self, indexPath) else { - return super._rx_collectionView(collectionView, canMoveItemAt: indexPath) + return false } return canMoveItem } - open override func _rx_collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { + open func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { self._sectionModels.moveFromSourceIndexPath(sourceIndexPath, destinationIndexPath: destinationIndexPath) - self.moveItem?(self, sourceIndexPath, destinationIndexPath) + self.moveItem(self, sourceIndexPath, destinationIndexPath) } } diff --git a/Sources/RxDataSources/Deprecated.swift b/Sources/RxDataSources/Deprecated.swift new file mode 100644 index 00000000..2578ba6e --- /dev/null +++ b/Sources/RxDataSources/Deprecated.swift @@ -0,0 +1,19 @@ +// +// Deprecated.swift +// RxDataSources +// +// Created by Krunoslav Zaher on 10/8/17. +// Copyright © 2017 kzaher. All rights reserved. +// + +extension CollectionViewSectionedDataSource { + @available(*, deprecated, renamed: "configureSupplementaryView") + open var supplementaryViewFactory: ConfigureSupplementaryView { + get { + return self.configureSupplementaryView + } + set { + self.configureSupplementaryView = newValue + } + } +} diff --git a/Sources/RxDataSources/RxCollectionViewSectionedAnimatedDataSource.swift b/Sources/RxDataSources/RxCollectionViewSectionedAnimatedDataSource.swift index 8a3c0f44..b65d521c 100644 --- a/Sources/RxDataSources/RxCollectionViewSectionedAnimatedDataSource.swift +++ b/Sources/RxDataSources/RxCollectionViewSectionedAnimatedDataSource.swift @@ -23,21 +23,24 @@ open class RxCollectionViewSectionedAnimatedDataSource , RxCollectionViewDataSourceType { public typealias Element = [S] - public var animationConfiguration = AnimationConfiguration() - - // For some inexplicable reason, when doing animated updates first time - // it crashes. Still need to figure out that one. - var dataSet = false - - private let disposeBag = DisposeBag() - // This subject and throttle are here - // because collection view has problems processing animated updates fast. - // This should somewhat help to alleviate the problem. - private let partialUpdateEvent = PublishSubject<(UICollectionView, Event)>() + // animation configuration + public var animationConfiguration: AnimationConfiguration - public override init() { - super.init() + public init( + animationConfiguration: AnimationConfiguration = AnimationConfiguration(), + configureCell: @escaping ConfigureCell, + configureSupplementaryView: @escaping ConfigureSupplementaryView, + moveItem: @escaping MoveItem = { _, _, _ in () }, + canMoveItemAtIndexPath: @escaping CanMoveItemAtIndexPath = { _, _ in false } + ) { + self.animationConfiguration = animationConfiguration + super.init( + configureCell: configureCell, + configureSupplementaryView: configureSupplementaryView, + moveItem: moveItem, + canMoveItemAtIndexPath: canMoveItemAtIndexPath + ) self.partialUpdateEvent // so in case it does produce a crash, it will be after the data has changed @@ -51,6 +54,17 @@ open class RxCollectionViewSectionedAnimatedDataSource)>() + /** This method exists because collection view updates are throttled because of internal collection view bugs. Collection view behaves poorly during fast updates, so this should remedy those issues. diff --git a/Sources/RxDataSources/RxCollectionViewSectionedReloadDataSource.swift b/Sources/RxDataSources/RxCollectionViewSectionedReloadDataSource.swift index c4f6b5ae..08b37b6b 100644 --- a/Sources/RxDataSources/RxCollectionViewSectionedReloadDataSource.swift +++ b/Sources/RxDataSources/RxCollectionViewSectionedReloadDataSource.swift @@ -21,10 +21,6 @@ open class RxCollectionViewSectionedReloadDataSource public typealias Element = [S] - public override init() { - super.init() - } - open func collectionView(_ collectionView: UICollectionView, observedEvent: Event) { Binder(self) { dataSource, element in #if DEBUG diff --git a/Sources/RxDataSources/RxTableViewSectionedAnimatedDataSource.swift b/Sources/RxDataSources/RxTableViewSectionedAnimatedDataSource.swift index 0086c9ee..5356a869 100644 --- a/Sources/RxDataSources/RxTableViewSectionedAnimatedDataSource.swift +++ b/Sources/RxDataSources/RxTableViewSectionedAnimatedDataSource.swift @@ -20,13 +20,53 @@ open class RxTableViewSectionedAnimatedDataSource , RxTableViewDataSourceType { public typealias Element = [S] - public var animationConfiguration = AnimationConfiguration() - var dataSet = false + /// Animation configuration for data source + public var animationConfiguration: AnimationConfiguration - public override init() { - super.init() - } + #if os(iOS) + public init( + animationConfiguration: AnimationConfiguration = AnimationConfiguration(), + configureCell: @escaping ConfigureCell, + titleForHeaderInSection: @escaping TitleForHeaderInSection = { _, _ in nil }, + titleForFooterInSection: @escaping TitleForFooterInSection = { _, _ in nil }, + canEditRowAtIndexPath: @escaping CanEditRowAtIndexPath = { _, _ in false }, + canMoveRowAtIndexPath: @escaping CanMoveRowAtIndexPath = { _, _ in false }, + sectionIndexTitles: @escaping SectionIndexTitles = { _ in nil }, + sectionForSectionIndexTitle: @escaping SectionForSectionIndexTitle = { _, _, index in index } + ) { + self.animationConfiguration = animationConfiguration + super.init( + configureCell: configureCell, + titleForHeaderInSection: titleForHeaderInSection, + titleForFooterInSection: titleForFooterInSection, + canEditRowAtIndexPath: canEditRowAtIndexPath, + canMoveRowAtIndexPath: canMoveRowAtIndexPath, + sectionIndexTitles: sectionIndexTitles, + sectionForSectionIndexTitle: sectionForSectionIndexTitle + ) + } + #else + public init( + animationConfiguration: AnimationConfiguration = AnimationConfiguration(), + configureCell: @escaping ConfigureCell, + titleForHeaderInSection: @escaping TitleForHeaderInSection = { _, _ in nil }, + titleForFooterInSection: @escaping TitleForFooterInSection = { _, _ in nil }, + canEditRowAtIndexPath: @escaping CanEditRowAtIndexPath = { _, _ in false }, + canMoveRowAtIndexPath: @escaping CanMoveRowAtIndexPath = { _, _ in false } + ) { + self.animationConfiguration = animationConfiguration + super.init( + configureCell: configureCell, + titleForHeaderInSection: titleForHeaderInSection, + titleForFooterInSection: titleForFooterInSection, + canEditRowAtIndexPath: canEditRowAtIndexPath, + canMoveRowAtIndexPath: canMoveRowAtIndexPath + ) + } + #endif + + var dataSet = false open func tableView(_ tableView: UITableView, observedEvent: Event) { Binder(self) { dataSource, newSections in diff --git a/Sources/RxDataSources/RxTableViewSectionedReloadDataSource.swift b/Sources/RxDataSources/RxTableViewSectionedReloadDataSource.swift index 5031da4f..26629ce7 100644 --- a/Sources/RxDataSources/RxTableViewSectionedReloadDataSource.swift +++ b/Sources/RxDataSources/RxTableViewSectionedReloadDataSource.swift @@ -20,10 +20,6 @@ open class RxTableViewSectionedReloadDataSource , RxTableViewDataSourceType { public typealias Element = [S] - public override init() { - super.init() - } - open func tableView(_ tableView: UITableView, observedEvent: Event) { Binder(self) { dataSource, element in #if DEBUG diff --git a/Sources/RxDataSources/TableViewSectionedDataSource.swift b/Sources/RxDataSources/TableViewSectionedDataSource.swift index 9ecceb47..e2b48a60 100644 --- a/Sources/RxDataSources/TableViewSectionedDataSource.swift +++ b/Sources/RxDataSources/TableViewSectionedDataSource.swift @@ -14,101 +14,58 @@ import RxCocoa #endif import Differentiator -// objc monkey business -open class _TableViewSectionedDataSource +open class TableViewSectionedDataSource : NSObject - , UITableViewDataSource { - - open func _rx_numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - open func numberOfSections(in tableView: UITableView) -> Int { - return _rx_numberOfSections(in: tableView) - } - - open func _rx_tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 0 - } - - open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return _rx_tableView(tableView, numberOfRowsInSection: section) - } - - open func _rx_tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return (nil as UITableViewCell?)! - } - - open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return _rx_tableView(tableView, cellForRowAt: indexPath) - } - - open func _rx_tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return nil - } + , UITableViewDataSource + , SectionedViewDataSourceType { - open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return _rx_tableView(tableView, titleForHeaderInSection: section) - } + public typealias I = S.Item + public typealias Section = S - open func _rx_tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return nil - } - - open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return _rx_tableView(tableView, titleForFooterInSection: section) - } - - open func _rx_tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return false - } - - open func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return _rx_tableView(tableView, canEditRowAt: indexPath) - } - - open func _rx_tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - return false - } - - open func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - return _rx_tableView(tableView, canMoveRowAt: indexPath) - } + public typealias ConfigureCell = (TableViewSectionedDataSource, UITableView, IndexPath, I) -> UITableViewCell + public typealias TitleForHeaderInSection = (TableViewSectionedDataSource, Int) -> String? + public typealias TitleForFooterInSection = (TableViewSectionedDataSource, Int) -> String? + public typealias CanEditRowAtIndexPath = (TableViewSectionedDataSource, IndexPath) -> Bool + public typealias CanMoveRowAtIndexPath = (TableViewSectionedDataSource, IndexPath) -> Bool #if os(iOS) - open func _rx_sectionIndexTitles(for tableView: UITableView) -> [String]? { - return nil - } - - open func sectionIndexTitles(for tableView: UITableView) -> [String]? { - return _rx_sectionIndexTitles(for: tableView) - } - - open func _rx_tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { - return index - } - - open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { - return _rx_tableView(tableView, sectionForSectionIndexTitle: title, at: index) - } + public typealias SectionIndexTitles = (TableViewSectionedDataSource) -> [String]? + public typealias SectionForSectionIndexTitle = (TableViewSectionedDataSource, _ title: String, _ index: Int) -> Int #endif - open func _rx_tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - } - - open func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - _rx_tableView(tableView, moveRowAt: sourceIndexPath, to: destinationIndexPath) - } - -} - -open class TableViewSectionedDataSource - : _TableViewSectionedDataSource - , SectionedViewDataSourceType { - - public typealias I = S.Item - public typealias Section = S - public typealias CellFactory = (TableViewSectionedDataSource, UITableView, IndexPath, I) -> UITableViewCell + #if os(iOS) + public init( + configureCell: @escaping ConfigureCell, + titleForHeaderInSection: @escaping TitleForHeaderInSection = { _, _ in nil }, + titleForFooterInSection: @escaping TitleForFooterInSection = { _, _ in nil }, + canEditRowAtIndexPath: @escaping CanEditRowAtIndexPath = { _, _ in false }, + canMoveRowAtIndexPath: @escaping CanMoveRowAtIndexPath = { _, _ in false }, + sectionIndexTitles: @escaping SectionIndexTitles = { _ in nil }, + sectionForSectionIndexTitle: @escaping SectionForSectionIndexTitle = { _, _, index in index } + ) { + self.configureCell = configureCell + self.titleForHeaderInSection = titleForHeaderInSection + self.titleForFooterInSection = titleForFooterInSection + self.canEditRowAtIndexPath = canEditRowAtIndexPath + self.canMoveRowAtIndexPath = canMoveRowAtIndexPath + self.sectionIndexTitles = sectionIndexTitles + self.sectionForSectionIndexTitle = sectionForSectionIndexTitle + } + #else + public init( + configureCell: @escaping ConfigureCell, + titleForHeaderInSection: @escaping TitleForHeaderInSection = { _, _ in nil }, + titleForFooterInSection: @escaping TitleForFooterInSection = { _, _ in nil }, + canEditRowAtIndexPath: @escaping CanEditRowAtIndexPath = { _, _ in false }, + canMoveRowAtIndexPath: @escaping CanMoveRowAtIndexPath = { _, _ in false } + ) { + self.configureCell = configureCell + self.titleForHeaderInSection = titleForHeaderInSection + self.titleForFooterInSection = titleForFooterInSection + self.canEditRowAtIndexPath = canEditRowAtIndexPath + self.canMoveRowAtIndexPath = canMoveRowAtIndexPath + } + #endif #if DEBUG // If data source has already been bound, then mutating it @@ -160,7 +117,7 @@ open class TableViewSectionedDataSource self._sectionModels = sections.map { SectionModelSnapshot(model: $0, items: $0.items) } } - open var configureCell: CellFactory! = nil { + open var configureCell: ConfigureCell { didSet { #if DEBUG ensureNotMutatedAfterBinding() @@ -168,14 +125,14 @@ open class TableViewSectionedDataSource } } - open var titleForHeaderInSection: ((TableViewSectionedDataSource, Int) -> String?)? { + open var titleForHeaderInSection: TitleForHeaderInSection { didSet { #if DEBUG ensureNotMutatedAfterBinding() #endif } } - open var titleForFooterInSection: ((TableViewSectionedDataSource, Int) -> String?)? { + open var titleForFooterInSection: TitleForFooterInSection { didSet { #if DEBUG ensureNotMutatedAfterBinding() @@ -183,14 +140,14 @@ open class TableViewSectionedDataSource } } - open var canEditRowAtIndexPath: ((TableViewSectionedDataSource, IndexPath) -> Bool)? { + open var canEditRowAtIndexPath: CanEditRowAtIndexPath { didSet { #if DEBUG ensureNotMutatedAfterBinding() #endif } } - open var canMoveRowAtIndexPath: ((TableViewSectionedDataSource, IndexPath) -> Bool)? { + open var canMoveRowAtIndexPath: CanMoveRowAtIndexPath { didSet { #if DEBUG ensureNotMutatedAfterBinding() @@ -201,14 +158,14 @@ open class TableViewSectionedDataSource open var rowAnimation: UITableViewRowAnimation = .automatic #if os(iOS) - open var sectionIndexTitles: ((TableViewSectionedDataSource) -> [String]?)? { + open var sectionIndexTitles: SectionIndexTitles { didSet { #if DEBUG ensureNotMutatedAfterBinding() #endif } } - open var sectionForSectionIndexTitle:((TableViewSectionedDataSource, _ title: String, _ index: Int) -> Int)? { + open var sectionForSectionIndexTitle: SectionForSectionIndexTitle { didSet { #if DEBUG ensureNotMutatedAfterBinding() @@ -217,77 +174,51 @@ open class TableViewSectionedDataSource } #endif - public override init() { - super.init() - self.configureCell = { [weak self] _, _, _, _ in - if let strongSelf = self { - precondition(false, "There is a minor problem. `cellFactory` property on \(strongSelf) was not set. Please set it manually, or use one of the `rx_bindTo` methods.") - } - - return (nil as UITableViewCell!)! - } - } - + // UITableViewDataSource - open override func _rx_numberOfSections(in tableView: UITableView) -> Int { + open func numberOfSections(in tableView: UITableView) -> Int { return _sectionModels.count } - open override func _rx_tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { guard _sectionModels.count > section else { return 0 } return _sectionModels[section].items.count } - open override func _rx_tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { precondition(indexPath.item < _sectionModels[indexPath.section].items.count) return configureCell(self, tableView, indexPath, self[indexPath]) } - open override func _rx_tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return titleForHeaderInSection?(self, section) + open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return titleForHeaderInSection(self, section) } - - open override func _rx_tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return titleForFooterInSection?(self, section) + + open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + return titleForFooterInSection(self, section) } - open override func _rx_tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - guard let canEditRow = canEditRowAtIndexPath?(self, indexPath) else { - return super._rx_tableView(tableView, canEditRowAt: indexPath) - } - - return canEditRow + open func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return canEditRowAtIndexPath(self, indexPath) } - open override func _rx_tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - guard let canMoveRow = canMoveRowAtIndexPath?(self, indexPath) else { - return super._rx_tableView(tableView, canMoveRowAt: indexPath) - } - - return canMoveRow + open func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { + return canMoveRowAtIndexPath(self, indexPath) } - open override func _rx_tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { + open func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { self._sectionModels.moveFromSourceIndexPath(sourceIndexPath, destinationIndexPath: destinationIndexPath) } #if os(iOS) - open override func _rx_sectionIndexTitles(for tableView: UITableView) -> [String]? { - guard let titles = sectionIndexTitles?(self) else { - return super._rx_sectionIndexTitles(for: tableView) - } - - return titles + open func sectionIndexTitles(for tableView: UITableView) -> [String]? { + return sectionIndexTitles(self) } - open override func _rx_tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { - guard let section = sectionForSectionIndexTitle?(self, title, index) else { - return super._rx_tableView(tableView, sectionForSectionIndexTitle: title, at: index) - } - - return section + open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { + return sectionForSectionIndexTitle(self, title, index) } #endif }