From 24dc2c6fe01a0fdc315fc2fbb633d459bbc55958 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Fri, 24 Jul 2015 16:47:49 +0200 Subject: [PATCH] Fixes problem with issues/67. --- .../Implementations/ObservableBase.swift | 2 +- .../Implementations/RefCount.swift | 3 +- .../Observers/AutoDetachObserver.swift | 14 ++- .../Tests/AnonymousObservable+Test.swift | 89 +++++++++++++++++++ .../Tests/Observable+BindingTest.swift | 2 +- RxTests/RxTests.xcodeproj/project.pbxproj | 12 ++- 6 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift diff --git a/RxSwift/RxSwift/Observables/Implementations/ObservableBase.swift b/RxSwift/RxSwift/Observables/Implementations/ObservableBase.swift index f38ccb9b..f01d6432 100644 --- a/RxSwift/RxSwift/Observables/Implementations/ObservableBase.swift +++ b/RxSwift/RxSwift/Observables/Implementations/ObservableBase.swift @@ -16,7 +16,7 @@ public class ObservableBase : Observable { let disposable = subscribeCore(ObserverOf(autoDetachObserver)) autoDetachObserver.setDisposable(disposable) - return disposable + return autoDetachObserver } func subscribeCore(observer: ObserverOf) -> Disposable { diff --git a/RxSwift/RxSwift/Observables/Implementations/RefCount.swift b/RxSwift/RxSwift/Observables/Implementations/RefCount.swift index f12fc0b3..6150f97e 100644 --- a/RxSwift/RxSwift/Observables/Implementations/RefCount.swift +++ b/RxSwift/RxSwift/Observables/Implementations/RefCount.swift @@ -25,9 +25,8 @@ class RefCount_ : Sink, ObserverType { self.parent.lock.performLocked { if state.count == 0 { - let disposable = self.parent.source.connect() self.parent.state.count = 1 - self.parent.state.connectableSubscription = disposable + self.parent.state.connectableSubscription = self.parent.source.connect() } else { self.parent.state.count = state.count + 1 diff --git a/RxSwift/RxSwift/Observers/AutoDetachObserver.swift b/RxSwift/RxSwift/Observers/AutoDetachObserver.swift index a54f55e1..2c42a7e5 100644 --- a/RxSwift/RxSwift/Observers/AutoDetachObserver.swift +++ b/RxSwift/RxSwift/Observers/AutoDetachObserver.swift @@ -9,8 +9,9 @@ import Foundation class AutoDetachObserver : ObserverBase { - private let observer : O + private var observer : O? private let m : SingleAssignmentDisposable + private var observerLock = Lock() init(observer: O) { self.observer = observer @@ -24,12 +25,16 @@ class AutoDetachObserver : ObserverBase { } override func onCore(event: Event) { + let observer = self.observerLock.calculateLocked { + return self.observer + } + switch event { case .Next: - observer.on(event) + trySend(observer, event) case .Completed: fallthrough case .Error: - observer.on(event) + trySend(observer, event) dispose() } } @@ -37,5 +42,8 @@ class AutoDetachObserver : ObserverBase { override func dispose() { super.dispose() m.dispose() + observerLock.performLocked { + self.observer = nil + } } } \ No newline at end of file diff --git a/RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift b/RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift new file mode 100644 index 00000000..c56f4162 --- /dev/null +++ b/RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift @@ -0,0 +1,89 @@ +// +// AnonymousObservable+Test.swift +// RxTests +// +// Created by Krunoslav Zaher on 7/24/15. +// +// + +import Foundation +import RxSwift +import XCTest + +class AnonymousObservableTests : RxTest { + +} + +extension AnonymousObservableTests { + func testAnonymousObservable_detachesOnDispose() { + var observer: ObserverOf! + let a = create { o in + observer = o + return NopDisposable.instance + } as Observable + + var elements = [Int]() + + let d = a >- subscribeNext { n in + elements.append(n) + } + + XCTAssertEqual(elements, []) + + sendNext(observer, 0) + XCTAssertEqual(elements, [0]) + + d.dispose() + + sendNext(observer, 1) + XCTAssertEqual(elements, [0]) + } + + func testAnonymousObservable_detachesOnComplete() { + var observer: ObserverOf! + let a = create { o in + observer = o + return NopDisposable.instance + } as Observable + + var elements = [Int]() + + let d = a >- subscribeNext { n in + elements.append(n) + } + + XCTAssertEqual(elements, []) + + sendNext(observer, 0) + XCTAssertEqual(elements, [0]) + + sendCompleted(observer) + + sendNext(observer, 1) + XCTAssertEqual(elements, [0]) + } + + func testAnonymousObservable_detachesOnError() { + var observer: ObserverOf! + let a = create { o in + observer = o + return NopDisposable.instance + } as Observable + + var elements = [Int]() + + let d = a >- subscribeNext { n in + elements.append(n) + } + + XCTAssertEqual(elements, []) + + sendNext(observer, 0) + XCTAssertEqual(elements, [0]) + + sendError(observer, testError) + + sendNext(observer, 1) + XCTAssertEqual(elements, [0]) + } +} \ No newline at end of file diff --git a/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift b/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift index 133dbd80..46d495c5 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift @@ -260,7 +260,7 @@ extension ObservableBindingTest { func testReplay_DeadlockErrorAfterN() { var nEvents = 0 - let observable = concat([returnElements(0, 1, 2), failWith(testError)]) >- replay(3) >- refCount + let observable = concat([returnElements(0, 1, 2), failWith(testError)])// >- replay(3) >- refCount let _d = observable >- subscribeError { n in nEvents++ } >- scopedDispose diff --git a/RxTests/RxTests.xcodeproj/project.pbxproj b/RxTests/RxTests.xcodeproj/project.pbxproj index 413bb8e4..0c2b5860 100644 --- a/RxTests/RxTests.xcodeproj/project.pbxproj +++ b/RxTests/RxTests.xcodeproj/project.pbxproj @@ -85,6 +85,8 @@ C8AF26EF1B499E5C00131C03 /* DelegateProxyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8AF26EE1B499E5C00131C03 /* DelegateProxyTest.swift */; }; C8AF26F01B499E5C00131C03 /* DelegateProxyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8AF26EE1B499E5C00131C03 /* DelegateProxyTest.swift */; }; C8B5BEA11B4A6A82000D732C /* RxCocoaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B5BEA01B4A6A82000D732C /* RxCocoaTests.swift */; }; + C8B605EC1B6260A10044410E /* AnonymousObservable+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B605EB1B6260A10044410E /* AnonymousObservable+Test.swift */; }; + C8B605ED1B6260A10044410E /* AnonymousObservable+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B605EB1B6260A10044410E /* AnonymousObservable+Test.swift */; }; C8B787FA1AF55CDE00206D02 /* Observable+ConcurrencyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B787F91AF55CDE00206D02 /* Observable+ConcurrencyTest.swift */; }; C8CDD7CB1B52B0730043F0C5 /* RxBlocking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8CDD7CA1B52B0730043F0C5 /* RxBlocking.framework */; }; C8CDD7D41B52BEC40043F0C5 /* Observable+BlockingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8CDD7D31B52BEC40043F0C5 /* Observable+BlockingTest.swift */; }; @@ -143,6 +145,7 @@ C897EC491B1123DA009C2CB0 /* Observable+MultipleTest+Zip.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+MultipleTest+Zip.swift"; sourceTree = ""; }; C8AF26EE1B499E5C00131C03 /* DelegateProxyTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelegateProxyTest.swift; sourceTree = ""; }; C8B5BEA01B4A6A82000D732C /* RxCocoaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCocoaTests.swift; sourceTree = ""; }; + C8B605EB1B6260A10044410E /* AnonymousObservable+Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AnonymousObservable+Test.swift"; sourceTree = ""; }; C8B787F91AF55CDE00206D02 /* Observable+ConcurrencyTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+ConcurrencyTest.swift"; sourceTree = ""; }; C8CDD7CA1B52B0730043F0C5 /* RxBlocking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = RxBlocking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C8CDD7D31B52BEC40043F0C5 /* Observable+BlockingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+BlockingTest.swift"; sourceTree = ""; }; @@ -281,25 +284,26 @@ C811083F1AF50E2A001C13E4 /* Tests */ = { isa = PBXGroup; children = ( + C8B605EB1B6260A10044410E /* AnonymousObservable+Test.swift */, C81108401AF50E2A001C13E4 /* AssumptionsTest.swift */, + C897EC3A1B10E000009C2CB0 /* BehaviorSubjectTest.swift */, C81108411AF50E2A001C13E4 /* ConcurrencyTest.swift */, + C8AF26EE1B499E5C00131C03 /* DelegateProxyTest.swift */, C81108421AF50E2A001C13E4 /* DisposableTest.swift */, C81108431AF50E2A001C13E4 /* Observable+AggregateTest.swift */, C81108441AF50E2A001C13E4 /* Observable+BindingTest.swift */, C8CDD7D31B52BEC40043F0C5 /* Observable+BlockingTest.swift */, C8B787F91AF55CDE00206D02 /* Observable+ConcurrencyTest.swift */, + C81108471AF50E2A001C13E4 /* Observable+MultipleTest.swift */, C81108451AF50E2A001C13E4 /* Observable+MultipleTest+CombineLatest.swift */, C81108461AF50E2A001C13E4 /* Observable+MultipleTest+CombineLatest.tt */, C897EC491B1123DA009C2CB0 /* Observable+MultipleTest+Zip.swift */, C897EC461B112070009C2CB0 /* Observable+MultipleTest+Zip.tt */, - C81108471AF50E2A001C13E4 /* Observable+MultipleTest.swift */, C81108481AF50E2A001C13E4 /* Observable+SingleTest.swift */, C81108491AF50E2A001C13E4 /* Observable+StandardSequenceOperatorsTest.swift */, C811084A1AF50E2A001C13E4 /* Observable+TimeTest.swift */, C811084B1AF50E2A001C13E4 /* QueueTests.swift */, C814CEA21AF5622600E98087 /* VariableTest.swift */, - C897EC3A1B10E000009C2CB0 /* BehaviorSubjectTest.swift */, - C8AF26EE1B499E5C00131C03 /* DelegateProxyTest.swift */, ); path = Tests; sourceTree = ""; @@ -435,6 +439,7 @@ C81108521AF50E2A001C13E4 /* MockObserver.swift in Sources */, C8633AE51B0A9FF300375D60 /* KVOObservableTests.swift in Sources */, C811085C1AF50E2A001C13E4 /* TestExtensions.swift in Sources */, + C8B605EC1B6260A10044410E /* AnonymousObservable+Test.swift in Sources */, C811085D1AF50E2A001C13E4 /* AssumptionsTest.swift in Sources */, C81108501AF50E2A001C13E4 /* ConnectableObservable.swift in Sources */, C814CEA31AF5622600E98087 /* VariableTest.swift in Sources */, @@ -466,6 +471,7 @@ C88BB8A01B07E64B0064D411 /* Observable+StandardSequenceOperatorsTest.swift in Sources */, C88BB8A11B07E64B0064D411 /* Observable+MultipleTest.swift in Sources */, C81CC92C1B513FD400915606 /* NSObject+RxTests.swift in Sources */, + C8B605ED1B6260A10044410E /* AnonymousObservable+Test.swift in Sources */, C88BB8A21B07E64B0064D411 /* ColdObservable.swift in Sources */, C88BB8A31B07E64B0064D411 /* HotObservable.swift in Sources */, C8FDC5F91B2B5B7E0065F8D9 /* ElementIndexPair.swift in Sources */,