Skip to content

Instantly share code, notes, and snippets.

@ncreated
Last active February 20, 2017 20:14
Show Gist options
  • Save ncreated/780c58c25d0731b93f9106be694adebe to your computer and use it in GitHub Desktop.
Save ncreated/780c58c25d0731b93f9106be694adebe to your computer and use it in GitHub Desktop.
Comparison of Imperative vs Reactive ways
// Imperative
protocol EditableMapSourceDelegate: class {
func sourceDidChangeActiveTerritory(_ source: EditableMapSource)
func sourceDidChangeData(_ source: MapDataSource)
}
final class EditableMapSource: MapDataSource {
weak var delegate: EditableMapSourceDelegate?
// ...
private(set) var territories: [TerritoryData] = [] {
didSet {
delegate?.sourceDidChangeData(self)
}
}
private(set) var activeTerritory: TerritoryData? {
didSet {
delegate?.sourceDidChangeActiveTerritory(self)
}
}
var activeTerritoryIndex: Int? {
if let activeTerritory = activeTerritory {
return territories.index(of: activeTerritory)
} else {
return nil
}
}
// MARK: Navigating between territories
func moveToNextTerritory() {
if let index = activeTerritoryIndex {
let nextIndex = (index + 1) % territories.count
activeTerritory = territories[nextIndex]
}
}
func moveToPreviousTerritory() {
if let index = activeTerritoryIndex {
let previousIndex = (index > 0) ? (index - 1) : (territories.count - 1)
activeTerritory = territories[previousIndex]
}
}
// ...
// MARK: Editing territories
func hexBelongsToTerritory(_ hex: Hex) throws -> Bool {
// ...
}
func addHexToTerritory(_ hex: Hex) throws {
// ...
}
func removeHexFromTerritory(_ hex: Hex) throws {
// ...
}
// ...
func changeNumberOfUnitsInTerritoryByValue(_ value: Int) throws {
// ...
}
// ...
}
// Reactive
final class EditorViewModel {
// ...
private let stateVariable: Variable<EditorState>
private let disposeBag = DisposeBag()
// ...
// MARK: - Inputs
func set(hexSelected rx_hexSelected: Observable<Hex>,
nextTerritory rx_next: Observable<Void>,
previousTerritory rx_previous: Observable<Void>,
moreUnits rx_more: Observable<Void>,
lessUnits rx_less: Observable<Void>)
{
let rx_state = stateVariable.asObservable()
let rx_territoryIndexChange = Observable
.of( rx_next.map { 1 }, rx_previous.map { -1 } )
.merge()
let rx_numberOfUnitsChange = Observable
.of( rx_more.map { 1 }, rx_less.map { -1 } )
.merge()
// Calculate state changes
let rx_stateAfterProcessingHex = rx_hexSelected
.withLatestFrom(rx_state) { $0 }
.map { (hex, state) in state.nextByProcessing(hex: hex) }
let rx_stateAfterChangingActiveTerritory = rx_territoryIndexChange
.withLatestFrom(rx_state) { $0 }
.map { (change, state) in state.nextByChangingActiveIndex(by: change) }
let rx_stateAfterChangingNumberOfUnits = rx_numberOfUnitsChange
.withLatestFrom(rx_state) { $0 }
.map { (change, state) in state.nextByChangingNumberOfUnits(by: change) }
// Update state variable
Observable
.of(rx_stateAfterProcessingHex, rx_stateAfterChangingActiveTerritory, rx_stateAfterChangingNumberOfUnits)
.merge()
.bindTo(stateVariable)
.addDisposableTo(disposeBag)
// Create outputs
rx_viewData = rx_state
.map { state in
return (map: CustomMapSource(territories: state.territories, colorsOrder: colors),
current: Territory(data: state.currentActive),
previous: state.previousActive.map { Territory(data: $0) } )
}
.asDriver(onErrorDriveWith: .empty())
// ...
}
// MARK: - Outputs
private(set) var rx_viewData: Driver<(map: MapDataSource, current: Territory, previous: Territory?)> = .never()
}
struct EditorState {
// MARK: - Properties
let territories: [TerritoryData]
let currentActive: TerritoryData
let previousActive: TerritoryData?
// ...
// MARK: - Public
func nextByProcessing(hex: Hex) -> EditorState {
// ...
}
func nextByChangingActiveIndex(by change: Int) -> EditorState {
// ...
}
func nextByChangingNumberOfUnits(by change: Int) -> EditorState {
// ...
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment