From 4a99e422b87cdfe2813d1667ee2add13eaa404cd Mon Sep 17 00:00:00 2001 From: Fabian Ehrentraud Date: Tue, 8 Mar 2016 09:34:00 +0100 Subject: [PATCH 1/6] added IntegratedReactiveViewController and IntegratedReactiveGestureReactor --- .../Project/RFP.xcodeproj/project.pbxproj | 12 ++- .../IntegratedReactiveGestureReactor.swift | 85 ++++++++++++++++ .../IntegratedReactiveViewController.swift | 98 +++++++++++++++++++ 3 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift create mode 100644 functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift diff --git a/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj b/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj index 892fd22..de39f6f 100644 --- a/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj +++ b/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj @@ -16,6 +16,9 @@ 0C18B47D1C4454580081DFC5 /* ImperativeGestureReactorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C18B47C1C4454580081DFC5 /* ImperativeGestureReactorTests.swift */; }; 0C9FFB351C46625F00FD6C05 /* ReactiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C9FFB341C46625F00FD6C05 /* ReactiveViewController.swift */; }; 0CDDAB481C56C21C00D5DA3D /* ReactiveShortViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CDDAB471C56C21C00D5DA3D /* ReactiveShortViewController.swift */; }; + 1BF29EDA1C69E72D00912AD3 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF29ED91C69E72D00912AD3 /* UIView+Extensions.swift */; }; + 1F5B23AC1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5B23AB1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift */; }; + 1F5B23AE1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5B23AD1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift */; }; 1FB180CC1C6C72EF008BC2D1 /* UIGestureRecognizerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB180CB1C6C72EF008BC2D1 /* UIGestureRecognizerProtocol.swift */; }; 1FD5DC431C69D4B60050B3D9 /* ImperativeGestureReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD5DC421C69D4B60050B3D9 /* ImperativeGestureReactor.swift */; }; 1FD5DC451C69D60C0050B3D9 /* GestureReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD5DC441C69D60C0050B3D9 /* GestureReactor.swift */; }; @@ -24,7 +27,6 @@ 1FE3E4371C6CF6B800804CA2 /* ReactiveTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FE3E4361C6CF6B800804CA2 /* ReactiveTimer.swift */; }; 1FE3E4391C6DC6CC00804CA2 /* GestureReactorTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FE3E4381C6DC6CB00804CA2 /* GestureReactorTestHelper.swift */; }; 1FE3E43B1C6E40A200804CA2 /* ReactiveGestureReactorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FE3E43A1C6E40A200804CA2 /* ReactiveGestureReactorTests.swift */; }; - 1BF29EDA1C69E72D00912AD3 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF29ED91C69E72D00912AD3 /* UIView+Extensions.swift */; }; B48DEEE7DD9FCD9E8F77A13B /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA3577BA56804CC07EC782AF /* Pods.framework */; }; /* End PBXBuildFile section */ @@ -53,6 +55,9 @@ 0C9FFB341C46625F00FD6C05 /* ReactiveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactiveViewController.swift; sourceTree = ""; }; 0CDDAB471C56C21C00D5DA3D /* ReactiveShortViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactiveShortViewController.swift; sourceTree = ""; }; 1AFF0EC5CED5C7CDACEDF353 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + 1BF29ED91C69E72D00912AD3 /* UIView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; + 1F5B23AB1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegratedReactiveGestureReactor.swift; sourceTree = ""; }; + 1F5B23AD1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegratedReactiveViewController.swift; sourceTree = ""; }; 1FB180CB1C6C72EF008BC2D1 /* UIGestureRecognizerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIGestureRecognizerProtocol.swift; sourceTree = ""; }; 1FD5DC421C69D4B60050B3D9 /* ImperativeGestureReactor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImperativeGestureReactor.swift; sourceTree = ""; }; 1FD5DC441C69D60C0050B3D9 /* GestureReactor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureReactor.swift; sourceTree = ""; }; @@ -61,7 +66,6 @@ 1FE3E4361C6CF6B800804CA2 /* ReactiveTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactiveTimer.swift; sourceTree = ""; }; 1FE3E4381C6DC6CB00804CA2 /* GestureReactorTestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureReactorTestHelper.swift; sourceTree = ""; }; 1FE3E43A1C6E40A200804CA2 /* ReactiveGestureReactorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactiveGestureReactorTests.swift; sourceTree = ""; }; - 1BF29ED91C69E72D00912AD3 /* UIView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; 350C6FD680F3FD2ADAEA261D /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; AA3577BA56804CC07EC782AF /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -124,6 +128,8 @@ 1FB180CB1C6C72EF008BC2D1 /* UIGestureRecognizerProtocol.swift */, 1FE3E4341C6C782F00804CA2 /* TimerProtocol.swift */, 1FE3E4361C6CF6B800804CA2 /* ReactiveTimer.swift */, + 1F5B23AB1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift */, + 1F5B23AD1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift */, ); path = RFP; sourceTree = ""; @@ -315,6 +321,8 @@ 0C18B4681C4454580081DFC5 /* AppDelegate.swift in Sources */, 1FD5DC431C69D4B60050B3D9 /* ImperativeGestureReactor.swift in Sources */, 0C153D611C4F001300CBD947 /* Observable+Extension.swift in Sources */, + 1F5B23AC1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift in Sources */, + 1F5B23AE1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift in Sources */, 0CDDAB481C56C21C00D5DA3D /* ReactiveShortViewController.swift in Sources */, 1FD5DC451C69D60C0050B3D9 /* GestureReactor.swift in Sources */, 1FE3E4351C6C782F00804CA2 /* TimerProtocol.swift in Sources */, diff --git a/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift new file mode 100644 index 0000000..f53af07 --- /dev/null +++ b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift @@ -0,0 +1,85 @@ +import Foundation +import UIKit +import RxSwift +import RxCocoa + + +// same implementation as ReactiveGestureReactor, but not using GestureReactor protocol, rather directly using Rx events +class IntegratedReactiveGestureReactor { + + var delegate: GestureReactorDelegate? + + private let timerCreator: ReactiveTimerCreator + private let disposeBag = DisposeBag() + + init(timerCreator: ReactiveTimerCreator, panGestureEvent: ControlEvent, rotateGestureEvent: ControlEvent) { + + self.timerCreator = timerCreator + + // FYI + // Passing on the UIGesture at this point is dodgy as it's a reference + // It's state will change and render our filter useless. + // We therefore keep just the state in our observable buffers [.Began,.Began,.Ended] + let rotateGesturesStartedEnded = rotateGestureEvent.filter { gesture in gesture.state == .Began || gesture.state == .Ended}.flatMap { (gesture) -> Observable in + return Observable.just(gesture.state) + } + + let panGesturesStartedEnded = panGestureEvent.filter { gesture in gesture.state == .Began || gesture.state == .Ended}.flatMap { (gesture) -> Observable in + return Observable.just(gesture.state) + } + + // Combine our latest .Began and .Ended from both Pan and Rotate. + // If they are the same then return the same state. If not then return a Failed. + let combineStartEndGestures = Observable.combineLatest(panGesturesStartedEnded, rotateGesturesStartedEnded) { (panState, rotateState) -> Observable in + + // If only one is .Ended, the result is .Ended too + var state = UIGestureRecognizerState.Ended + if panState == .Began && rotateState == .Began { + state = .Began + } + + return Observable.just(state) + }.switchLatest() + + // several .Began events in a row are to be treated the same as a single one, it has just meaning if a .Ended is in between + let distinceCombineStartEndGestures = combineStartEndGestures.distinctUntilChanged() + + + // condition: when both pan and rotate has begun + let bothGesturesStarted = distinceCombineStartEndGestures.filter { (state) -> Bool in + state == .Began + } + + // condition: when both pan and rotate has Ended + let bothGesturesEnded = distinceCombineStartEndGestures.filter { (state) -> Bool in + state == .Ended + } + + // when bothGesturesStarted, do this: + bothGesturesStarted.subscribeNext { [unowned self] _ in + + self.delegate?.didStart() + // create a timer that ticks every second + let timer = self.timerCreator(interval: 1) + // condition: but only three ticks + let timerThatTicksThree = timer.take(4) + // condition: and also, stop it immediately when both pan and rotate ended + let timerThatTicksThreeAndStops = timerThatTicksThree.takeUntil(bothGesturesEnded) + + timerThatTicksThreeAndStops.subscribe(onNext: { [unowned self] count in + // the imperative version waits for a second until didComplete is called, so we have to tick once more, but do not send the last tick to the delegate + guard count < 4 else { + return + //do nothing + } + // when a tick happens, do this: + self.delegate?.didTick(3 - count) + }, onCompleted: { [unowned self] in + // when the timer completes, do this: + self.delegate?.didComplete() + }) + }.addDisposableTo(self.disposeBag) + + } + +} diff --git a/functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift b/functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift new file mode 100644 index 0000000..a3a333f --- /dev/null +++ b/functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift @@ -0,0 +1,98 @@ +// +// ViewController.swift +// RFP +// +// Created by Mark Aron Szulyovszky on 11/01/2016. +// Copyright © 2016 Mark Aron Szulyovszky. All rights reserved. +// + +import UIKit +import RxSwift +import RxCocoa + +class IntegratedReactiveViewController: UIViewController, SetStatus, GestureReactorDelegate { + + @IBOutlet weak var draggableView: UIView! + @IBOutlet weak var statusLabel: UILabel! + @IBOutlet weak var centerXConstraint: NSLayoutConstraint! //For updating the position of the box when dragging + @IBOutlet weak var centerYConstraint: NSLayoutConstraint! + + private let pan: UIPanGestureRecognizer + private let rotate: UIRotationGestureRecognizer + private var gestureReactor: IntegratedReactiveGestureReactor + + private let disposeBag = DisposeBag() + + required init?(coder aDecoder: NSCoder) { + pan = UIPanGestureRecognizer() + rotate = UIRotationGestureRecognizer() + gestureReactor = IntegratedReactiveGestureReactor(timerCreator: { interval in ReactiveTimerFactory.reactiveTimer(interval: interval) }, panGestureEvent: pan.rx_event, rotateGestureEvent: rotate.rx_event) + + super.init(coder: aDecoder) + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + pan = UIPanGestureRecognizer() + rotate = UIRotationGestureRecognizer() + gestureReactor = IntegratedReactiveGestureReactor(timerCreator: { interval in ReactiveTimerFactory.reactiveTimer(interval: interval) }, panGestureEvent: pan.rx_event, rotateGestureEvent: rotate.rx_event) + + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + override func viewDidLoad() { + super.viewDidLoad() + + gestureReactor.delegate = self + + self.draggableView.gestureRecognizers = [pan, rotate] + + + /// + /// + /// Extra Code to manipulate move and rotate the subview. + /// + /// Uses custom infix on CGPoint to '-' or '+' two together. + + let panLocation = pan.rx_event.map { [unowned self] in + $0.locationInView(self.view) - self.view.center + } + panLocation.map { $0.x } + .bindTo(self.centerXConstraint.rx_constant) + .addDisposableTo(self.disposeBag) + + panLocation.map { $0.y } + .bindTo(self.centerYConstraint.rx_constant) + .addDisposableTo(self.disposeBag) + + rotate.rx_event + .map { ($0 as! UIRotationGestureRecognizer).rotation } + .bindTo(self.draggableView.rx_rotate) + .addDisposableTo(self.disposeBag) + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(animated) + self.setStatus("Status: Waiting for Rotate & Pan") + } + + func didStart() { + self.setStatus("Started") + } + + func didTick(secondsLeft: Int) { + self.setStatus("Tick: \(secondsLeft)") + } + + func didComplete() { + self.setStatus("Completed") + } + +} + +extension IntegratedReactiveViewController: UIGestureRecognizerDelegate { + + func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + return true + } + +} From 71d9d57ae7f8a2ebf566ff26a9adac120993c3b0 Mon Sep 17 00:00:00 2001 From: Fabian Ehrentraud Date: Tue, 8 Mar 2016 09:59:51 +0100 Subject: [PATCH 2/6] added IntegratedReactiveGestureReactorTests, does not yet compile - mockPanGestureEvent and mockRotateGestureEvent still need to be implemented --- .../Project/RFP.xcodeproj/project.pbxproj | 4 + ...ntegratedReactiveGestureReactorTests.swift | 400 ++++++++++++++++++ 2 files changed, 404 insertions(+) create mode 100644 functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift diff --git a/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj b/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj index de39f6f..fbe9795 100644 --- a/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj +++ b/functional-reactive-intuition/Project/RFP.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 1BF29EDA1C69E72D00912AD3 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF29ED91C69E72D00912AD3 /* UIView+Extensions.swift */; }; 1F5B23AC1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5B23AB1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift */; }; 1F5B23AE1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5B23AD1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift */; }; + 1F5B23B01C8EC62100F28DE1 /* IntegratedReactiveGestureReactorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5B23AF1C8EC62100F28DE1 /* IntegratedReactiveGestureReactorTests.swift */; }; 1FB180CC1C6C72EF008BC2D1 /* UIGestureRecognizerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB180CB1C6C72EF008BC2D1 /* UIGestureRecognizerProtocol.swift */; }; 1FD5DC431C69D4B60050B3D9 /* ImperativeGestureReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD5DC421C69D4B60050B3D9 /* ImperativeGestureReactor.swift */; }; 1FD5DC451C69D60C0050B3D9 /* GestureReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD5DC441C69D60C0050B3D9 /* GestureReactor.swift */; }; @@ -58,6 +59,7 @@ 1BF29ED91C69E72D00912AD3 /* UIView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; 1F5B23AB1C8EBA7B00F28DE1 /* IntegratedReactiveGestureReactor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegratedReactiveGestureReactor.swift; sourceTree = ""; }; 1F5B23AD1C8EBCAD00F28DE1 /* IntegratedReactiveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegratedReactiveViewController.swift; sourceTree = ""; }; + 1F5B23AF1C8EC62100F28DE1 /* IntegratedReactiveGestureReactorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegratedReactiveGestureReactorTests.swift; sourceTree = ""; }; 1FB180CB1C6C72EF008BC2D1 /* UIGestureRecognizerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIGestureRecognizerProtocol.swift; sourceTree = ""; }; 1FD5DC421C69D4B60050B3D9 /* ImperativeGestureReactor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImperativeGestureReactor.swift; sourceTree = ""; }; 1FD5DC441C69D60C0050B3D9 /* GestureReactor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureReactor.swift; sourceTree = ""; }; @@ -141,6 +143,7 @@ 0C18B47E1C4454580081DFC5 /* Info.plist */, 1FE3E4381C6DC6CB00804CA2 /* GestureReactorTestHelper.swift */, 1FE3E43A1C6E40A200804CA2 /* ReactiveGestureReactorTests.swift */, + 1F5B23AF1C8EC62100F28DE1 /* IntegratedReactiveGestureReactorTests.swift */, ); path = RFPTests; sourceTree = ""; @@ -337,6 +340,7 @@ files = ( 1FE3E4391C6DC6CC00804CA2 /* GestureReactorTestHelper.swift in Sources */, 1FE3E43B1C6E40A200804CA2 /* ReactiveGestureReactorTests.swift in Sources */, + 1F5B23B01C8EC62100F28DE1 /* IntegratedReactiveGestureReactorTests.swift in Sources */, 0C18B47D1C4454580081DFC5 /* ImperativeGestureReactorTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift b/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift new file mode 100644 index 0000000..a37d687 --- /dev/null +++ b/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift @@ -0,0 +1,400 @@ +import XCTest +import RxSwift +import RxCocoa +@testable import RFP + + +class IntegratedReactiveGestureReactorTests: XCTestCase { + + var sut: IntegratedReactiveGestureReactor! + var mockDelegate: MockGestureReactorDelegate! + var mockPanGestureEvent: ControlEvent! + var mockRotateGestureEvent: ControlEvent! + var mockTimerCreatorCalled = 0 + // FIXME cannot be weak, so we cannot test the same way as in ImperativeGestureReactorTests + var mockTimer: MockReactiveTimer? + + override func setUp() { + super.setUp() +// mockPanGestureEvent = ??? +// mockRotateGestureEvent = ??? + let timerCreator: ReactiveTimerCreator = { [unowned self] interval in + self.mockTimerCreatorCalled += 1 + let mockTimer = MockReactiveTimer(interval: interval) + self.mockTimer = mockTimer + return mockTimer.asObservable().skip(1) + } + sut = IntegratedReactiveGestureReactor(timerCreator: timerCreator, panGestureEvent: mockPanGestureEvent, rotateGestureEvent: mockRotateGestureEvent) + mockDelegate = MockGestureReactorDelegate() + sut.delegate = mockDelegate + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testDoNothing() { + XCTAssertNil(mockTimer) + XCTAssertEqual(mockDelegate.didStartCalled, 0) + XCTAssertEqual(mockDelegate.didTickCalled, 0) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, []) + XCTAssertEqual(mockTimerCreatorCalled, 0) + XCTAssertNil(mockTimer) + } + + func testBeganPanGesture() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 0) + XCTAssertEqual(mockDelegate.didTickCalled, 0) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, []) + XCTAssertEqual(mockTimerCreatorCalled, 0) + XCTAssertNil(mockTimer) + } + + func testBeganRotateGesture() { + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 0) + XCTAssertEqual(mockDelegate.didTickCalled, 0) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, []) + XCTAssertEqual(mockTimerCreatorCalled, 0) + XCTAssertNil(mockTimer) + } + + func testBeganPanEndedPanBeganRotateGesture() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 0) + XCTAssertEqual(mockDelegate.didTickCalled, 0) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, []) + XCTAssertEqual(mockTimerCreatorCalled, 0) + XCTAssertNil(mockTimer) + } + + func testBeganBothGestures() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 0) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, []) + XCTAssertEqual(mockTimerCreatorCalled, 1) + XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndEndedRotate() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 0) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, []) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNil(mockTimer) + } + + func testBeganBothGesturesAndTickedOnce() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 1) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2]) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedOnceAndEndedRotate() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 1) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2]) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNil(mockTimer) + } + + func testBeganBothGesturesAndTickedTwice() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 2) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1]) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedThrice() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 3) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFrice() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 3) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndPanEnded() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 3) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNil(mockTimer) + } + + func testBeganBothGesturesAndTickedTwiceAndPanEndedAndPanBeganAgain() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 2) + XCTAssertEqual(mockDelegate.didTickCalled, 2) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1]) + XCTAssertEqual(mockTimerCreatorCalled, 2) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndPanBeganAgain_ignoreAdditionalBegans() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 0) + XCTAssertEqual(mockDelegate.didCompleteCalled, 0) + XCTAssertEqual(mockDelegate.tickSecondsLefts, []) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndPanBeganAgain() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 1) + XCTAssertEqual(mockDelegate.didTickCalled, 3) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 1) + // XCTAssertNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndEndedPanGestureAndBeganPanAgain() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 2) + XCTAssertEqual(mockDelegate.didTickCalled, 3) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 2) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndEndedRotateGestureAndBeganRotateAgain() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 2) + XCTAssertEqual(mockDelegate.didTickCalled, 3) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 2) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgain() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 2) + XCTAssertEqual(mockDelegate.didTickCalled, 3) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 2) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedOnce() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + + XCTAssertEqual(mockDelegate.didStartCalled, 2) + XCTAssertEqual(mockDelegate.didTickCalled, 4) + XCTAssertEqual(mockDelegate.didCompleteCalled, 1) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0, 2]) + XCTAssertEqual(mockTimerCreatorCalled, 2) + // XCTAssertNotNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedFrice() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + + XCTAssertEqual(mockDelegate.didStartCalled, 2) + XCTAssertEqual(mockDelegate.didTickCalled, 6) + XCTAssertEqual(mockDelegate.didCompleteCalled, 2) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0, 2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 2) + // XCTAssertNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedFriceAndEndedBothGestures() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + + XCTAssertEqual(mockDelegate.didStartCalled, 2) + XCTAssertEqual(mockDelegate.didTickCalled, 6) + XCTAssertEqual(mockDelegate.didCompleteCalled, 2) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0, 2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 2) + // XCTAssertNil(mockTimer) + } + + func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedFriceAndEndedBothGesturesAndStartedBothAgain() { + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + mockTimer!.mockExecuteOnTick() + sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + sut.handlePan(MockPanGestureRecognizer(state: .Began)) + + XCTAssertEqual(mockDelegate.didStartCalled, 3) + XCTAssertEqual(mockDelegate.didTickCalled, 6) + XCTAssertEqual(mockDelegate.didCompleteCalled, 2) + XCTAssertEqual(mockDelegate.tickSecondsLefts, [2, 1, 0, 2, 1, 0]) + XCTAssertEqual(mockTimerCreatorCalled, 3) + // XCTAssertNotNil(mockTimer) + } + +} From d3c73b360a6c87058cb9952fc39df4f7317f8024 Mon Sep 17 00:00:00 2001 From: Fabian Ehrentraud Date: Tue, 8 Mar 2016 10:50:41 +0100 Subject: [PATCH 3/6] exchanged events with observables in order to be able to directly provide Observable to IntegratedReactiveGestureReactor --- .../IntegratedReactiveGestureReactor.swift | 6 ++--- .../IntegratedReactiveViewController.swift | 23 +++++++++++++++++-- ...ntegratedReactiveGestureReactorTests.swift | 10 ++++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift index f53af07..99af3ba 100644 --- a/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift +++ b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift @@ -12,7 +12,7 @@ class IntegratedReactiveGestureReactor { private let timerCreator: ReactiveTimerCreator private let disposeBag = DisposeBag() - init(timerCreator: ReactiveTimerCreator, panGestureEvent: ControlEvent, rotateGestureEvent: ControlEvent) { + init(timerCreator: ReactiveTimerCreator, panGestureObservable: Observable, rotateGestureObservable: Observable) { self.timerCreator = timerCreator @@ -20,11 +20,11 @@ class IntegratedReactiveGestureReactor { // Passing on the UIGesture at this point is dodgy as it's a reference // It's state will change and render our filter useless. // We therefore keep just the state in our observable buffers [.Began,.Began,.Ended] - let rotateGesturesStartedEnded = rotateGestureEvent.filter { gesture in gesture.state == .Began || gesture.state == .Ended}.flatMap { (gesture) -> Observable in + let rotateGesturesStartedEnded = rotateGestureObservable.filter { gesture in gesture.state == .Began || gesture.state == .Ended}.flatMap { (gesture) -> Observable in return Observable.just(gesture.state) } - let panGesturesStartedEnded = panGestureEvent.filter { gesture in gesture.state == .Began || gesture.state == .Ended}.flatMap { (gesture) -> Observable in + let panGesturesStartedEnded = panGestureObservable.filter { gesture in gesture.state == .Began || gesture.state == .Ended}.flatMap { (gesture) -> Observable in return Observable.just(gesture.state) } diff --git a/functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift b/functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift index a3a333f..4a7be9a 100644 --- a/functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift +++ b/functional-reactive-intuition/Project/RFP/IntegratedReactiveViewController.swift @@ -26,15 +26,34 @@ class IntegratedReactiveViewController: UIViewController, SetStatus, GestureReac required init?(coder aDecoder: NSCoder) { pan = UIPanGestureRecognizer() rotate = UIRotationGestureRecognizer() - gestureReactor = IntegratedReactiveGestureReactor(timerCreator: { interval in ReactiveTimerFactory.reactiveTimer(interval: interval) }, panGestureEvent: pan.rx_event, rotateGestureEvent: rotate.rx_event) + + // workaround to convert ControlEvent to Observable + let panObservable: Observable = pan.rx_event.asObservable().flatMap { gesture -> Observable in + return Observable.just(gesture as UIGestureRecognizerType) + } + let rotateObservable: Observable = rotate.rx_event.asObservable().flatMap { gesture -> Observable in + return Observable.just(gesture as UIGestureRecognizerType) + } + + gestureReactor = IntegratedReactiveGestureReactor(timerCreator: { interval in ReactiveTimerFactory.reactiveTimer(interval: interval) }, panGestureObservable: panObservable, rotateGestureObservable: rotateObservable) super.init(coder: aDecoder) } + // TODO as we like to have non-optional and non-implicitly-unwrapped properties, we need to execute the setup code in both initializers - unfortunately we can not call instance helper functions here with the current version of swift override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { pan = UIPanGestureRecognizer() rotate = UIRotationGestureRecognizer() - gestureReactor = IntegratedReactiveGestureReactor(timerCreator: { interval in ReactiveTimerFactory.reactiveTimer(interval: interval) }, panGestureEvent: pan.rx_event, rotateGestureEvent: rotate.rx_event) + + // workaround to convert ControlEvent to Observable + let panObservable: Observable = pan.rx_event.asObservable().flatMap { gesture -> Observable in + return Observable.just(gesture as UIGestureRecognizerType) + } + let rotateObservable: Observable = rotate.rx_event.asObservable().flatMap { gesture -> Observable in + return Observable.just(gesture as UIGestureRecognizerType) + } + + gestureReactor = IntegratedReactiveGestureReactor(timerCreator: { interval in ReactiveTimerFactory.reactiveTimer(interval: interval) }, panGestureObservable: panObservable, rotateGestureObservable: rotateObservable) super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } diff --git a/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift b/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift index a37d687..6d2f929 100644 --- a/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift +++ b/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift @@ -8,23 +8,23 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { var sut: IntegratedReactiveGestureReactor! var mockDelegate: MockGestureReactorDelegate! - var mockPanGestureEvent: ControlEvent! - var mockRotateGestureEvent: ControlEvent! + var mockPanGestureObservable: Observable! + var mockRotateGestureObservable: Observable! var mockTimerCreatorCalled = 0 // FIXME cannot be weak, so we cannot test the same way as in ImperativeGestureReactorTests var mockTimer: MockReactiveTimer? override func setUp() { super.setUp() -// mockPanGestureEvent = ??? -// mockRotateGestureEvent = ??? +// mockPanGestureObservable = ??? +// mockRotateGestureObservable = ??? let timerCreator: ReactiveTimerCreator = { [unowned self] interval in self.mockTimerCreatorCalled += 1 let mockTimer = MockReactiveTimer(interval: interval) self.mockTimer = mockTimer return mockTimer.asObservable().skip(1) } - sut = IntegratedReactiveGestureReactor(timerCreator: timerCreator, panGestureEvent: mockPanGestureEvent, rotateGestureEvent: mockRotateGestureEvent) + sut = IntegratedReactiveGestureReactor(timerCreator: timerCreator, panGestureObservable: mockPanGestureObservable, rotateGestureObservable: mockRotateGestureObservable) mockDelegate = MockGestureReactorDelegate() sut.delegate = mockDelegate } From bb5c96e416c33a24d8ccd67c39786c422c0582d7 Mon Sep 17 00:00:00 2001 From: Fabian Ehrentraud Date: Tue, 8 Mar 2016 10:58:08 +0100 Subject: [PATCH 4/6] modify IntegratedReactiveGestureReactorTests to compile, still 2 tests fail --- ...ntegratedReactiveGestureReactorTests.swift | 170 +++++++++--------- 1 file changed, 87 insertions(+), 83 deletions(-) diff --git a/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift b/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift index 6d2f929..94d61b8 100644 --- a/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift +++ b/functional-reactive-intuition/Project/RFPTests/IntegratedReactiveGestureReactorTests.swift @@ -10,14 +10,18 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { var mockDelegate: MockGestureReactorDelegate! var mockPanGestureObservable: Observable! var mockRotateGestureObservable: Observable! + var mockPanVariable: Variable! + var mockRotateVariable: Variable! var mockTimerCreatorCalled = 0 // FIXME cannot be weak, so we cannot test the same way as in ImperativeGestureReactorTests var mockTimer: MockReactiveTimer? override func setUp() { super.setUp() -// mockPanGestureObservable = ??? -// mockRotateGestureObservable = ??? + mockPanVariable = Variable(MockPanGestureRecognizer(state: .Possible)) + mockRotateVariable = Variable(MockRotateGestureRecognizer(state: .Possible)) + mockPanGestureObservable = mockPanVariable.asObservable().skip(1) + mockRotateGestureObservable = mockRotateVariable.asObservable().skip(1) let timerCreator: ReactiveTimerCreator = { [unowned self] interval in self.mockTimerCreatorCalled += 1 let mockTimer = MockReactiveTimer(interval: interval) @@ -45,7 +49,7 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganPanGesture() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 0) XCTAssertEqual(mockDelegate.didTickCalled, 0) @@ -56,7 +60,7 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganRotateGesture() { - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 0) XCTAssertEqual(mockDelegate.didTickCalled, 0) @@ -67,9 +71,9 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganPanEndedPanBeganRotateGesture() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 0) XCTAssertEqual(mockDelegate.didTickCalled, 0) @@ -80,8 +84,8 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGestures() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 1) XCTAssertEqual(mockDelegate.didTickCalled, 0) @@ -92,9 +96,9 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndEndedRotate() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) XCTAssertEqual(mockDelegate.didStartCalled, 1) XCTAssertEqual(mockDelegate.didTickCalled, 0) @@ -105,8 +109,8 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedOnce() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() XCTAssertEqual(mockDelegate.didStartCalled, 1) @@ -118,10 +122,10 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedOnceAndEndedRotate() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) XCTAssertEqual(mockDelegate.didStartCalled, 1) XCTAssertEqual(mockDelegate.didTickCalled, 1) @@ -132,8 +136,8 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedTwice() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() @@ -146,8 +150,8 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedThrice() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() @@ -161,8 +165,8 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFrice() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() @@ -177,13 +181,13 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndPanEnded() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) XCTAssertEqual(mockDelegate.didStartCalled, 1) XCTAssertEqual(mockDelegate.didTickCalled, 3) @@ -194,12 +198,12 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedTwiceAndPanEndedAndPanBeganAgain() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 2) XCTAssertEqual(mockDelegate.didTickCalled, 2) @@ -210,12 +214,12 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndPanBeganAgain_ignoreAdditionalBegans() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 1) XCTAssertEqual(mockDelegate.didTickCalled, 0) @@ -226,13 +230,13 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndPanBeganAgain() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 1) XCTAssertEqual(mockDelegate.didTickCalled, 3) @@ -243,14 +247,14 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndEndedPanGestureAndBeganPanAgain() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 2) XCTAssertEqual(mockDelegate.didTickCalled, 3) @@ -261,14 +265,14 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndEndedRotateGestureAndBeganRotateAgain() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 2) XCTAssertEqual(mockDelegate.didTickCalled, 3) @@ -279,16 +283,16 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgain() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 2) XCTAssertEqual(mockDelegate.didTickCalled, 3) @@ -299,16 +303,16 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedOnce() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() XCTAssertEqual(mockDelegate.didStartCalled, 2) @@ -320,16 +324,16 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedFrice() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() @@ -344,22 +348,22 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedFriceAndEndedBothGestures() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) XCTAssertEqual(mockDelegate.didStartCalled, 2) XCTAssertEqual(mockDelegate.didTickCalled, 6) @@ -370,24 +374,24 @@ class IntegratedReactiveGestureReactorTests: XCTestCase { } func testBeganBothGesturesAndTickedFriceAndEndedBothGesturesAndBeganBothAgainAndTickedFriceAndEndedBothGesturesAndStartedBothAgain() { - sut.handlePan(MockPanGestureRecognizer(state: .Began)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() mockTimer!.mockExecuteOnTick() - sut.handleRotate(MockRotateGestureRecognizer(state: .Ended)) - sut.handlePan(MockPanGestureRecognizer(state: .Ended)) - sut.handleRotate(MockRotateGestureRecognizer(state: .Began)) - sut.handlePan(MockPanGestureRecognizer(state: .Began)) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Ended) + mockPanVariable.value = MockPanGestureRecognizer(state: .Ended) + mockRotateVariable.value = MockRotateGestureRecognizer(state: .Began) + mockPanVariable.value = MockPanGestureRecognizer(state: .Began) XCTAssertEqual(mockDelegate.didStartCalled, 3) XCTAssertEqual(mockDelegate.didTickCalled, 6) From 37fb919905dde3f8fd246c063719bb17e4f7c2f9 Mon Sep 17 00:00:00 2001 From: Fabian Ehrentraud Date: Tue, 8 Mar 2016 13:02:36 +0100 Subject: [PATCH 5/6] fixed typo and wrong comments --- .../RFP/IntegratedReactiveGestureReactor.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift index 99af3ba..17a32a7 100644 --- a/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift +++ b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift @@ -42,16 +42,16 @@ class IntegratedReactiveGestureReactor { }.switchLatest() // several .Began events in a row are to be treated the same as a single one, it has just meaning if a .Ended is in between - let distinceCombineStartEndGestures = combineStartEndGestures.distinctUntilChanged() + let distinctCombineStartEndGestures = combineStartEndGestures.distinctUntilChanged() // condition: when both pan and rotate has begun - let bothGesturesStarted = distinceCombineStartEndGestures.filter { (state) -> Bool in + let bothGesturesStarted = distinctCombineStartEndGestures.filter { (state) -> Bool in state == .Began } - // condition: when both pan and rotate has Ended - let bothGesturesEnded = distinceCombineStartEndGestures.filter { (state) -> Bool in + // condition: when one of pan or rotate has Ended + let eitherGesturesEnded = distinctCombineStartEndGestures.filter { (state) -> Bool in state == .Ended } @@ -63,8 +63,8 @@ class IntegratedReactiveGestureReactor { let timer = self.timerCreator(interval: 1) // condition: but only three ticks let timerThatTicksThree = timer.take(4) - // condition: and also, stop it immediately when both pan and rotate ended - let timerThatTicksThreeAndStops = timerThatTicksThree.takeUntil(bothGesturesEnded) + // condition: and also, stop it immediately either pan or rotate ended + let timerThatTicksThreeAndStops = timerThatTicksThree.takeUntil(eitherGesturesEnded) timerThatTicksThreeAndStops.subscribe(onNext: { [unowned self] count in // the imperative version waits for a second until didComplete is called, so we have to tick once more, but do not send the last tick to the delegate From 8d283379eac57285a45358c1b42a720789fac1b7 Mon Sep 17 00:00:00 2001 From: Fabian Ehrentraud Date: Tue, 8 Mar 2016 15:32:48 +0100 Subject: [PATCH 6/6] fixed af41ec9 in IntegratedReactiveGestureReactor too --- .../Project/RFP/IntegratedReactiveGestureReactor.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift index 17a32a7..ae81f2e 100644 --- a/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift +++ b/functional-reactive-intuition/Project/RFP/IntegratedReactiveGestureReactor.swift @@ -68,12 +68,12 @@ class IntegratedReactiveGestureReactor { timerThatTicksThreeAndStops.subscribe(onNext: { [unowned self] count in // the imperative version waits for a second until didComplete is called, so we have to tick once more, but do not send the last tick to the delegate - guard count < 4 else { + guard count <= 2 else { return //do nothing } // when a tick happens, do this: - self.delegate?.didTick(3 - count) + self.delegate?.didTick(2 - count) }, onCompleted: { [unowned self] in // when the timer completes, do this: self.delegate?.didComplete()