Skip to content

Instantly share code, notes, and snippets.

@rlaguilar
Last active April 18, 2021 01:25
Show Gist options
  • Save rlaguilar/ca6840d3ea85dad733d0901b18e1be20 to your computer and use it in GitHub Desktop.
Save rlaguilar/ca6840d3ea85dad733d0901b18e1be20 to your computer and use it in GitHub Desktop.
RxSwift bug
//
// MazeViewController.swift
//
import UIKit
import Foundation
import RxSwift
class MazeViewController: UIViewController {
var currentDisposable: Disposable? = nil
var maze: ReactiveMaze!
var currentIteration: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib
}
@IBAction func generate(_ sender: Any) {
// cancel the current operation
self.currentDisposable?.dispose()
maze.cancel()
self.currentIteration += 1
self.currentDisposable = self.maze.generate(iteration: self.currentIteration)
.concatMap({
Observable.empty()
.delay(0.02, scheduler: MainScheduler.instance)
.startWith($0)
})
.observeOn(MainScheduler.instance)
.subscribe({ (event) in
switch event {
case .completed:
break
case .error(let err):
print(error)
case .next(let mazePayload):
// draw the new room
guard self.currentIteration == mazePayload.iteration else {
fatalError()
}
// do something expensive with the payload in the Main thread
}
})
}
}
//
// ReactiveMaze.swift
//
import Foundation
import RxSwift
/// Represents the state of a maze
class ReactiveMaze {
/// Maze explorer used to retreive the maze pieces
private let mazeExplorer: ReactiveMazeExplorer
/// Object used to downlaod the images for the rooms
private let imageDownloader: ReactiveImageDownloader
var currentIteration: Int = 0
init(imageDownloader: ReactiveImageDownloader, mazeExplorer: ReactiveMazeExplorer) {
self.mazeExplorer = mazeExplorer
self.imageDownloader = imageDownloader
}
/// Cancel the current exploration
func cancel() {
self.currentIteration = -1
self.mazeExplorer.cancel()
}
/// Starts exploring a new maze and retrieves its pieces.
///
/// - Warning: If there's some explorarion in progress it will be canceled
/// - Returns: The pieces of the new maze
func generate(iteration: Int) -> Observable<MazePayload> {
self.cancel()
self.currentIteration = iteration
let retrievedRoomsObservable = self.mazeExplorer.explore() // some observable with rooms
.concatMap { (room) -> Observable<RoomViewModel> in
// Retrieve the image for the received room
self.imageDownloader.retrieveImageData(fromUrl: room.tileUrl)
.map({ (data) -> RoomViewModel in
return RoomViewModel(room: room, withImageData: data)
})
}.observeOn(MainScheduler.instance)
return retrievedRoomsObservable
.filter { _ in self.currentIteration == iteration }
.map { room in
return MazePayload(room: room, iteration: iteration)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment