RxSwift/RxExample/RxExample/Examples/TableViewPartialUpdates/PartialUpdatesViewControlle...

189 lines
7.2 KiB
Swift

//
// PartialUpdatesViewController.swift
// RxExample
//
// Created by Krunoslav Zaher on 6/8/15.
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
import Foundation
import UIKit
#if !RX_NO_MODULE
import RxSwift
import RxCocoa
#endif
let generateCustomSize = true
let runAutomatically = false
let useAnimatedUpdateForCollectionView = false
/**
Code for reactive data sources is packed in [RxDataSources](https://github.com/RxSwiftCommunity/RxDataSources) project.
*/
class PartialUpdatesViewController : ViewController {
@IBOutlet weak var reloadTableViewOutlet: UITableView!
@IBOutlet weak var partialUpdatesTableViewOutlet: UITableView!
@IBOutlet weak var partialUpdatesCollectionViewOutlet: UICollectionView!
var timer: NSTimer? = nil
static let initialValue: [AnimatableSectionModel<String, Int>] = [
NumberSection(model: "section 1", items: [1, 2, 3]),
NumberSection(model: "section 2", items: [4, 5, 6]),
NumberSection(model: "section 3", items: [7, 8, 9]),
NumberSection(model: "section 4", items: [10, 11, 12]),
NumberSection(model: "section 5", items: [13, 14, 15]),
NumberSection(model: "section 6", items: [16, 17, 18]),
NumberSection(model: "section 7", items: [19, 20, 21]),
NumberSection(model: "section 8", items: [22, 23, 24]),
NumberSection(model: "section 9", items: [25, 26, 27]),
NumberSection(model: "section 10", items: [28, 29, 30])
]
static let firstChange: [AnimatableSectionModel<String, Int>]? = nil
var generator = Randomizer(rng: PseudoRandomGenerator(4, 3), sections: initialValue)
var sections = Variable([NumberSection]())
/**
Code for reactive data sources is packed in [RxDataSources](https://github.com/RxSwiftCommunity/RxDataSources) project.
*/
override func viewDidLoad() {
super.viewDidLoad()
// For UICollectionView, if another animation starts before previous one is finished, it will sometimes crash :(
// It's not deterministic (because Randomizer generates deterministic updates), and if you click fast
// It sometimes will and sometimes wont crash, depending on tapping speed.
// I guess you can maybe try some tricks with timeout, hard to tell :( That's on Apple side.
if generateCustomSize {
let nSections = 10
let nItems = 100
var sections = [AnimatableSectionModel<String, Int>]()
for i in 0 ..< nSections {
sections.append(AnimatableSectionModel(model: "Section \(i + 1)", items: Array(i * nItems ..< (i + 1) * nItems)))
}
generator = Randomizer(rng: PseudoRandomGenerator(4, 3), sections: sections)
}
#if runAutomatically
timer = NSTimer.scheduledTimerWithTimeInterval(0.6, target: self, selector: "randomize", userInfo: nil, repeats: true)
#endif
self.sections.value = generator.sections
let tvAnimatedDataSource = RxTableViewSectionedAnimatedDataSource<NumberSection>()
let reloadDataSource = RxTableViewSectionedReloadDataSource<NumberSection>()
skinTableViewDataSource(tvAnimatedDataSource)
skinTableViewDataSource(reloadDataSource)
self.sections.asObservable()
.bindTo(partialUpdatesTableViewOutlet.rx_itemsAnimatedWithDataSource(tvAnimatedDataSource))
.addDisposableTo(disposeBag)
self.sections.asObservable()
.bindTo(reloadTableViewOutlet.rx_itemsWithDataSource(reloadDataSource))
.addDisposableTo(disposeBag)
// Collection view logic works, but when clicking fast because of internal bugs
// collection view will sometimes get confused. I know what you are thinking,
// but this is really not a bug in the algorithm. The generated changes are
// pseudorandom, and crash happens depending on clicking speed.
//
// More info in `RxDataSourceStarterKit/README.md`
//
// If you want, turn this to true, just click slow :)
//
// While `useAnimatedUpdateForCollectionView` is false, you can click as fast as
// you want, table view doesn't seem to have same issues like collection view.
#if useAnimatedUpdateForCollectionView
let cvAnimatedDataSource = RxCollectionViewSectionedAnimatedDataSource<NumberSection>()
skinCollectionViewDataSource(cvAnimatedDataSource)
updates
.bindTo(partialUpdatesCollectionViewOutlet.rx_itemsWithDataSource(cvAnimatedDataSource))
.addDisposableTo(disposeBag)
#else
let cvReloadDataSource = RxCollectionViewSectionedReloadDataSource<NumberSection>()
skinCollectionViewDataSource(cvReloadDataSource)
self.sections.asObservable()
.bindTo(partialUpdatesCollectionViewOutlet.rx_itemsWithDataSource(cvReloadDataSource))
.addDisposableTo(disposeBag)
#endif
// touches
partialUpdatesCollectionViewOutlet.rx_itemSelected
.subscribeNext { [weak self] i in
print("Let me guess, it's .... It's \(self?.generator.sections[i.section].items[i.item]), isn't it? Yeah, I've got it.")
}
.addDisposableTo(disposeBag)
Observable.of(partialUpdatesTableViewOutlet.rx_itemSelected, reloadTableViewOutlet.rx_itemSelected)
.merge()
.subscribeNext { [weak self] i in
print("I have a feeling it's .... \(self?.generator.sections[i.section].items[i.item])?")
}
.addDisposableTo(disposeBag)
}
func skinTableViewDataSource(dataSource: RxTableViewSectionedDataSource<NumberSection>) {
dataSource.configureCell = { (_, tv, ip, i) in
let cell = tv.dequeueReusableCellWithIdentifier("Cell")
?? UITableViewCell(style:.Default, reuseIdentifier: "Cell")
cell.textLabel!.text = "\(i)"
return cell
}
dataSource.titleForHeaderInSection = { (ds, section: Int) -> String in
return dataSource.sectionAtIndex(section).model
}
}
func skinCollectionViewDataSource(dataSource: CollectionViewSectionedDataSource<NumberSection>) {
dataSource.cellFactory = { (_, cv, ip, i) in
let cell = cv.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: ip) as! NumberCell
cell.value!.text = "\(i)"
return cell
}
dataSource.supplementaryViewFactory = { (dataSource, cv, kind, ip) in
let section = cv.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "Section", forIndexPath: ip) as! NumberSectionView
section.value!.text = "\(dataSource.sectionAtIndex(ip.section).model)"
return section
}
}
override func viewWillDisappear(animated: Bool) {
self.timer?.invalidate()
}
@IBAction func randomize() {
generator.randomize()
var values = generator.sections
// useful for debugging
if PartialUpdatesViewController.firstChange != nil {
values = PartialUpdatesViewController.firstChange!
}
//print(values)
sections.value = values
}
}