Last active
February 5, 2016 17:05
-
-
Save almostintuitive/7fa9aa7fe1bb1b65ae36 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let pan = UIPanGestureRecognizer() | |
let pinch = UIPinchGestureRecognizer() | |
// Here, we want to create a signal that emits an event when the | |
// gesture has started. | |
// We can call .rx_event on UIPangestureRecognizer, and | |
// transform it's output into a signal, which then | |
// We can use filter to discard all other events! | |
let panStarted = pan.rx_event.filter { gesture in gesture.state == .Began } | |
// We do the same here, but this time we're only interested | |
// when the gestureRecognizer is in the .Ended state. | |
let panEnded = pan.rx_event.filter { gesture in gesture.state == .Ended } | |
let pinchStarted = pinch.rx_event.filter { gesture in gesture.state == .Began } | |
let pinchEnded = pinch.rx_event.filter { gesture in gesture.state == .Ended } | |
// Okay, let's think. Our aim is to only trigger the timer when both | |
// gestures began. We originally had to keep track of these states ourselves, | |
// but now that we transformed them into signals, we can also merge them, same | |
// way as you'd merge two arrays into one! | |
// Well, not exactly, we need a special combination, where the new signal will only | |
// start when both of its sub-signals have emitted an event: that's combineLatest(). | |
let bothGesturesStarted = Observable.combineLatest(panStarted, pinchStarted) { (_, _) -> Bool in return true } | |
// For gestures ended, we need merge(), since we don't need to wait until both of | |
// them has started, we can immediately forward events from both channels into | |
// the combined one. | |
let bothGesturesEnded = Observable.of(panEnded, pinchEnded).merge() | |
// Now that we have our starting point, what should we do? | |
// Signals are special beasts: you can subscribe to them. Same way as | |
// you'd subscribe to a notification through NSNotificationCenter. | |
// subscribeNext will take a closure (block), and every time the signal | |
// fires, it'll run the signal's emitted value through the block! | |
bothGesturesStarted.subscribeNext { _ in | |
// So, when bothGesturesStarted started, do this: | |
print("started") | |
// Now we need to create a timer. Rx is a quite comprehensive library, | |
// it has some really handy structures and extensions - one of them is | |
// exactly a timer. | |
// What do we want? If we don't want to keep track of any more state, | |
// we can just create a signal that emits a number (Int), and increase it | |
// on every 'tick'. | |
let timer = Observable<Int>.timer(1, period: 1, scheduler: MainScheduler.instance) | |
// But wait, we don't want this timer to go on indefinitely! | |
// Hmm, actually this is quite easy. Rx will also provide you operations | |
// where you can limit the lifetime of a signal. | |
// Same way as you'd take only the first 3 items in the array, you can | |
// use take(x) to only take the first x events (values) from a signal. | |
let timerThatTicksThree = timer.take(3) | |
// And finally, we can also combine signals in other ways: this time, | |
// we need to stop the timer signal when another signal is fired. | |
// Here, we just use takeUntil! It's like the "while" loop of signals. | |
let timerThatTicksThreeAndStops = timerThatTicksThree.takeUntil(bothGesturesEnded) | |
timerThatTicksThreeAndStops.subscribe(onNext: { count in | |
// when a tick happens, do this: | |
print("tick: \(count)") | |
}, onError: nil, onCompleted: { | |
// when the timer completes, do this: | |
print("completed") | |
}, onDisposed: nil) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment