From bd3c5a77b93a4ab763764d210c74f1deb197d2ae Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 25 Oct 2015 10:46:41 +0100 Subject: [PATCH 01/19] Removes hidden lamba allocations from disposables. --- RxSwift/Concurrency/Lock.swift | 8 +++ RxSwift/DataStructures/Bag.swift | 48 +++++++++++--- RxSwift/Disposables/CompositeDisposable.swift | 61 +++++++++--------- RxSwift/Disposables/DisposeBag.swift | 47 +++++++------- RxSwift/Disposables/SerialDisposable.swift | 23 +++---- .../SingleAssignmentDisposable.swift | 63 +++++++++---------- .../Observables/Implementations/Sink.swift | 40 ++++++------ 7 files changed, 163 insertions(+), 127 deletions(-) diff --git a/RxSwift/Concurrency/Lock.swift b/RxSwift/Concurrency/Lock.swift index 4fdfe3d8..5ec4a06d 100644 --- a/RxSwift/Concurrency/Lock.swift +++ b/RxSwift/Concurrency/Lock.swift @@ -17,6 +17,14 @@ struct SpinLock { init() { } + + mutating func lock() { + OSSpinLockLock(&_lock) + } + + mutating func unlock() { + OSSpinLockUnlock(&_lock) + } mutating func performLocked(@noescape action: () -> Void) { OSSpinLockLock(&_lock) diff --git a/RxSwift/DataStructures/Bag.swift b/RxSwift/DataStructures/Bag.swift index 0386e2f8..e9023b69 100644 --- a/RxSwift/DataStructures/Bag.swift +++ b/RxSwift/DataStructures/Bag.swift @@ -53,7 +53,7 @@ public struct Bag : CustomStringConvertible { private var _uniqueIdentity: Identity? private var _nextKey: ScopeUniqueTokenType = 0 - var pairs = [Entry]() + private var _pairs = [Entry]() /** Creates new empty `Bag`. @@ -89,7 +89,7 @@ public struct Bag : CustomStringConvertible { let key = BagKey(uniqueIdentity: _uniqueIdentity, key: _nextKey) - pairs.append(key: key, value: element) + _pairs.append(key: key, value: element) return key } @@ -98,14 +98,14 @@ public struct Bag : CustomStringConvertible { - returns: Number of elements in bag. */ public var count: Int { - return pairs.count + return _pairs.count } /** Removes all elements from bag and clears capacity. */ public mutating func removeAll() { - pairs.removeAll(keepCapacity: false) + _pairs.removeAll(keepCapacity: false) } /** @@ -115,10 +115,10 @@ public struct Bag : CustomStringConvertible { - returns: Element that bag contained, or nil in case element was already removed. */ public mutating func removeKey(key: BagKey) -> T? { - for i in 0 ..< pairs.count { - if pairs[i].key == key { - let value = pairs[i].value - pairs.removeAtIndex(i) + for i in 0 ..< _pairs.count { + if _pairs[i].key == key { + let value = _pairs[i].value + _pairs.removeAtIndex(i) return value } } @@ -127,6 +127,8 @@ public struct Bag : CustomStringConvertible { } } +// MARK: forEach + extension Bag { /** Enumerates elements inside the bag. @@ -134,10 +136,36 @@ extension Bag { - parameter action: Enumeration closure. */ public func forEach(@noescape action: (T) -> Void) { - let pairs = self.pairs + let pairs = self._pairs for i in 0 ..< pairs.count { action(pairs[i].value) } } -} \ No newline at end of file +} + +extension Bag where T: ObserverType { + /** + Dispatches `event` to app observers contained inside bag. + + - parameter action: Enumeration closure. + */ + public func on(event: Event) { + let pairs = self._pairs + + for i in 0 ..< pairs.count { + pairs[i].value.on(event) + } + } +} + +/** +Dispatches `dispose` to all disposables contained inside bag. +*/ +func disposeFromBag(bag: Bag) { + let pairs = bag._pairs + + for i in 0 ..< pairs.count { + pairs[i].value.dispose() + } +} diff --git a/RxSwift/Disposables/CompositeDisposable.swift b/RxSwift/Disposables/CompositeDisposable.swift index c49bad3c..b832f4c2 100644 --- a/RxSwift/Disposables/CompositeDisposable.swift +++ b/RxSwift/Disposables/CompositeDisposable.swift @@ -21,9 +21,8 @@ public class CompositeDisposable : DisposeBase, Disposable, Cancelable { public var disposed: Bool { get { - return _lock.calculateLocked { - return _disposables == nil - } + _lock.lock(); defer { _lock.unlock() } + return _disposables == nil } } @@ -55,7 +54,7 @@ public class CompositeDisposable : DisposeBase, Disposable, Cancelable { _disposables!.insert(disposable) } } - + /** Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed. @@ -64,27 +63,28 @@ public class CompositeDisposable : DisposeBase, Disposable, Cancelable { disposed `nil` will be returned. */ public func addDisposable(disposable: Disposable) -> DisposeKey? { - // this should be let - // bucause of compiler bug it's var - let key = _lock.calculateLocked { () -> DisposeKey? in - return _disposables?.insert(disposable) - } - + let key = _addDisposable(disposable) + if key == nil { disposable.dispose() } return key } + + private func _addDisposable(disposable: Disposable) -> DisposeKey? { + _lock.lock(); defer { _lock.unlock() } + + return _disposables?.insert(disposable) + } /** - returns: Gets the number of disposables contained in the `CompositeDisposable`. */ public var count: Int { get { - return _lock.calculateLocked { - return _disposables?.count ?? 0 - } + _lock.lock(); defer { _lock.unlock() } + return _disposables?.count ?? 0 } } @@ -94,30 +94,29 @@ public class CompositeDisposable : DisposeBase, Disposable, Cancelable { - parameter disposeKey: Key used to identify disposable to be removed. */ public func removeDisposable(disposeKey: DisposeKey) { - let disposable = _lock.calculateLocked { () -> Disposable? in - return _disposables?.removeKey(disposeKey) - } - - if let disposable = disposable { - disposable.dispose() - } + _removeDisposable(disposeKey)?.dispose() + } + + private func _removeDisposable(disposeKey: DisposeKey) -> Disposable? { + _lock.lock(); defer { _lock.unlock() } + return _disposables?.removeKey(disposeKey) } /** Disposes all disposables in the group and removes them from the group. */ public func dispose() { - let oldDisposables = _lock.calculateLocked { () -> Bag? in - let disposeBag = _disposables - _disposables = nil - - return disposeBag - } - - if let oldDisposables = oldDisposables { - oldDisposables.forEach { d in - d.dispose() - } + if let disposables = _dispose() { + disposeFromBag(disposables) } } + + private func _dispose() -> Bag? { + _lock.lock(); defer { _lock.unlock() } + + let disposeBag = _disposables + _disposables = nil + + return disposeBag + } } \ No newline at end of file diff --git a/RxSwift/Disposables/DisposeBag.swift b/RxSwift/Disposables/DisposeBag.swift index 28f6c09e..2c24a60e 100644 --- a/RxSwift/Disposables/DisposeBag.swift +++ b/RxSwift/Disposables/DisposeBag.swift @@ -52,38 +52,41 @@ public class DisposeBag: DisposeBase { - parameter disposable: Disposable to add. */ public func addDisposable(disposable: Disposable) { - let dispose = _lock.calculateLocked { () -> Bool in - if _disposed { - return true - } - - _disposables.append(disposable) - - return false - } - - if dispose { - disposable.dispose() + _addDisposable(disposable)?.dispose() + } + + private func _addDisposable(disposable: Disposable) -> Disposable? { + _lock.lock(); defer { _lock.unlock() } + if _disposed { + return disposable } + + _disposables.append(disposable) + + return nil } /** This is internal on purpose, take a look at `CompositeDisposable` instead. */ - func dispose() { - let oldDisposables = _lock.calculateLocked { () -> [Disposable] in - let disposables = _disposables - - _disposables.removeAll(keepCapacity: false) - _disposed = true - - return disposables - } - + private func dispose() { + let oldDisposables = _dispose() + for disposable in oldDisposables { disposable.dispose() } } + + private func _dispose() -> [Disposable] { + _lock.lock(); defer { _lock.unlock() } + + let disposables = _disposables + + _disposables.removeAll(keepCapacity: false) + _disposed = true + + return disposables + } deinit { dispose() diff --git a/RxSwift/Disposables/SerialDisposable.swift b/RxSwift/Disposables/SerialDisposable.swift index 571000cf..0f30324e 100644 --- a/RxSwift/Disposables/SerialDisposable.swift +++ b/RxSwift/Disposables/SerialDisposable.swift @@ -69,18 +69,19 @@ public class SerialDisposable : DisposeBase, Cancelable { Disposes the underlying disposable as well as all future replacements. */ public func dispose() { - let disposable: Disposable? = _lock.calculateLocked { - if _disposed { - return nil - } - else { - _disposed = true - return _current - } + _dispose()?.dispose() + } + + private func _dispose() -> Disposable? { + _lock.lock(); defer { _lock.unlock() } + if _disposed { + return nil } - - if let disposable = disposable { - disposable.dispose() + else { + _disposed = true + let current = _current + _current = nil + return current } } } \ No newline at end of file diff --git a/RxSwift/Disposables/SingleAssignmentDisposable.swift b/RxSwift/Disposables/SingleAssignmentDisposable.swift index bf7e3f21..8b2858bd 100644 --- a/RxSwift/Disposables/SingleAssignmentDisposable.swift +++ b/RxSwift/Disposables/SingleAssignmentDisposable.swift @@ -26,9 +26,7 @@ public class SingleAssignmentDisposable : DisposeBase, Disposable, Cancelable { */ public var disposed: Bool { get { - return _lock.calculateLocked { - return _disposed - } + return _disposed } } @@ -46,47 +44,44 @@ public class SingleAssignmentDisposable : DisposeBase, Disposable, Cancelable { */ public var disposable: Disposable { get { - return _lock.calculateLocked { - return _disposable ?? NopDisposable.instance - } + _lock.lock(); defer { _lock.unlock() } + return _disposable ?? NopDisposable.instance } set { - let disposable: Disposable? = _lock.calculateLocked { - if _disposableSet { - rxFatalError("oldState.disposable != nil") - } - - _disposableSet = true - - if _disposed { - return newValue - } - - _disposable = newValue - - return nil - } - - if let disposable = disposable { - disposable.dispose() - } + _setDisposable(newValue)?.dispose() } } + private func _setDisposable(newValue: Disposable) -> Disposable? { + if _disposableSet { + rxFatalError("oldState.disposable != nil") + } + + _disposableSet = true + + if _disposed { + return newValue + } + + _disposable = newValue + + return nil + } + /** Disposes the underlying disposable. */ public func dispose() { - let disposable: Disposable? = _lock.calculateLocked { - _disposed = true - let dispose = _disposable - _disposable = nil + _dispose()?.dispose() + } - return dispose - } + private func _dispose() -> Disposable? { + _lock.lock(); defer { _lock.unlock() } - if let disposable = disposable { - disposable.dispose() - } + _disposed = true + let disposable = _disposable + _disposable = nil + + return disposable } } diff --git a/RxSwift/Observables/Implementations/Sink.swift b/RxSwift/Observables/Implementations/Sink.swift index c7b16261..7aeaee53 100644 --- a/RxSwift/Observables/Implementations/Sink.swift +++ b/RxSwift/Observables/Implementations/Sink.swift @@ -18,13 +18,15 @@ class Sink : Disposable { var observer: O? { get { - return _lock.calculateLocked { _observer } + _lock.lock(); defer { _lock.unlock() } + return _observer } } var cancel: Disposable { get { - return _lock.calculateLocked { _cancel } + _lock.lock(); defer { _lock.unlock() } + return _cancel } } @@ -35,25 +37,25 @@ class Sink : Disposable { _observer = observer _cancel = cancel } - - func dispose() { - let cancel: Disposable? = _lock.calculateLocked { - if _disposed { - return nil - } - - let cancel = _cancel - - _disposed = true - _observer = nil - _cancel = NopDisposable.instance - - return cancel + + func _disposeInternal() -> Disposable? { + _lock.lock(); defer { _lock.unlock() } + + if _disposed { + return nil } - if let cancel = cancel { - cancel.dispose() - } + let cancel = _cancel + + _disposed = true + _observer = nil + _cancel = NopDisposable.instance + + return cancel + } + + func dispose() { + _disposeInternal()?.dispose() } deinit { From 26a34c4ac3d7647af4475590fd97ebfacc54dcd2 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 25 Oct 2015 11:43:21 +0100 Subject: [PATCH 02/19] Makes `Producer` internal. --- .../Observables/Implementations/KVOObservable.swift | 9 ++++++--- RxCocoa/Common/Observables/NSObject+Rx.swift | 2 +- RxSwift/Observables/Implementations/Producer.swift | 12 +++--------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/RxCocoa/Common/Observables/Implementations/KVOObservable.swift b/RxCocoa/Common/Observables/Implementations/KVOObservable.swift index 06577002..c5a0bac2 100644 --- a/RxCocoa/Common/Observables/Implementations/KVOObservable.swift +++ b/RxCocoa/Common/Observables/Implementations/KVOObservable.swift @@ -11,8 +11,11 @@ import Foundation import RxSwift #endif -class KVOObservable : _Producer - , KVOObservableProtocol { +class KVOObservable + : ObservableType + , KVOObservableProtocol { + typealias E = Element? + unowned var target: AnyObject var strongTarget: AnyObject? @@ -30,7 +33,7 @@ class KVOObservable : _Producer } } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + func subscribe(observer: O) -> Disposable { let observer = KVOObserver(parent: self) { (value) in if value as? NSNull != nil { observer.on(.Next(nil)) diff --git a/RxCocoa/Common/Observables/NSObject+Rx.swift b/RxCocoa/Common/Observables/NSObject+Rx.swift index d61992c6..4f3acd33 100644 --- a/RxCocoa/Common/Observables/NSObject+Rx.swift +++ b/RxCocoa/Common/Observables/NSObject+Rx.swift @@ -59,7 +59,7 @@ extension NSObject { - returns: Observable sequence of objects on `keyPath`. */ public func rx_observe(keyPath: String, options: NSKeyValueObservingOptions = [.New, .Initial], retainSelf: Bool = true) -> Observable { - return KVOObservable(object: self, keyPath: keyPath, options: options, retainTarget: retainSelf) + return KVOObservable(object: self, keyPath: keyPath, options: options, retainTarget: retainSelf).asObservable() } } diff --git a/RxSwift/Observables/Implementations/Producer.swift b/RxSwift/Observables/Implementations/Producer.swift index c1d32a08..63c38c76 100644 --- a/RxSwift/Observables/Implementations/Producer.swift +++ b/RxSwift/Observables/Implementations/Producer.swift @@ -8,18 +8,12 @@ import Foundation -public class _Producer : Producer { - public override init() { - super.init() - } -} - -public class Producer : Observable { +class Producer : Observable { override init() { super.init() } - public override func subscribe(observer: O) -> Disposable { + override func subscribe(observer: O) -> Disposable { let sink = SingleAssignmentDisposable() let subscription = SingleAssignmentDisposable() @@ -43,7 +37,7 @@ public class Producer : Observable { return d } - public func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { abstractMethod() } } \ No newline at end of file From 2e8dbb7af9417e45165b377fb16a79097160b7f7 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 25 Oct 2015 11:43:38 +0100 Subject: [PATCH 03/19] Turns on `-OWhole-module-optimization` for `Release` configuration. --- Rx.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index f23e198c..2d4a3dea 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -3051,6 +3051,7 @@ MTL_ENABLE_DEBUG_INFO = NO; OTHER_SWIFT_FLAGS = "-D TRACE_RESOURCES"; SDKROOT = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -3225,6 +3226,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; From dcc65e8fe000a12eb1337e22a5b10c7b67e5dd23 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 25 Oct 2015 21:16:36 +0100 Subject: [PATCH 04/19] Adds synchronization protocols to reduce allocations. --- Rx.xcodeproj/project.pbxproj | 60 +++++++++ RxExample/RxExample.xcodeproj/project.pbxproj | 28 +++- RxSwift/Concurrency/Lock.swift | 7 +- RxSwift/Concurrency/LockOwnerType.swift | 23 ++++ .../Concurrency/SynchronizedDisposeType.swift | 20 +++ RxSwift/Concurrency/SynchronizedOnType.swift | 20 +++ .../SynchronizedSubscribeType.swift | 20 +++ .../SynchronizedUnsubscribeType.swift | 22 ++++ RxSwift/DataStructures/Bag.swift | 2 +- .../Disposables/SubscriptionDisposable.swift | 23 ++++ .../Implementations/CombineLatest.swift | 33 +++-- .../Implementations/ShareReplay1.swift | 93 +++++++------ .../Schedulers/CurrentThreadScheduler.swift | 94 +++++++++---- RxSwift/Subjects/BehaviorSubject.swift | 2 +- RxSwift/Subjects/PublishSubject.swift | 123 ++++++++---------- RxSwift/Subjects/ReplaySubject.swift | 4 +- RxSwift/Subjects/Variable.swift | 12 +- RxTests/PerformanceTests/main.swift | 77 +---------- .../Mocks/HotObservable.swift | 2 +- .../Mocks/PrimitiveHotObservable.swift | 2 +- RxTests/RxTests.xcodeproj/project.pbxproj | 3 + RxTests/Tests/PerformanceTools.swift | 114 ++++++++++++++++ 22 files changed, 550 insertions(+), 234 deletions(-) create mode 100644 RxSwift/Concurrency/LockOwnerType.swift create mode 100644 RxSwift/Concurrency/SynchronizedDisposeType.swift create mode 100644 RxSwift/Concurrency/SynchronizedOnType.swift create mode 100644 RxSwift/Concurrency/SynchronizedSubscribeType.swift create mode 100644 RxSwift/Concurrency/SynchronizedUnsubscribeType.swift create mode 100644 RxSwift/Disposables/SubscriptionDisposable.swift diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index 2d4a3dea..e7949ad6 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -298,6 +298,30 @@ C84CC5411BDC3B3E00E06A64 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC53F1BDC3B3700E06A64 /* ElementAt.swift */; }; C84CC5421BDC3B3E00E06A64 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC53F1BDC3B3700E06A64 /* ElementAt.swift */; }; C84CC5431BDC3B3E00E06A64 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC53F1BDC3B3700E06A64 /* ElementAt.swift */; }; + C84CC54E1BDCF48200E06A64 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC54D1BDCF48200E06A64 /* LockOwnerType.swift */; }; + C84CC54F1BDCF48200E06A64 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC54D1BDCF48200E06A64 /* LockOwnerType.swift */; }; + C84CC5501BDCF48200E06A64 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC54D1BDCF48200E06A64 /* LockOwnerType.swift */; }; + C84CC5511BDCF48200E06A64 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC54D1BDCF48200E06A64 /* LockOwnerType.swift */; }; + C84CC5531BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5521BDCF49300E06A64 /* SynchronizedOnType.swift */; }; + C84CC5541BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5521BDCF49300E06A64 /* SynchronizedOnType.swift */; }; + C84CC5551BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5521BDCF49300E06A64 /* SynchronizedOnType.swift */; }; + C84CC5561BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5521BDCF49300E06A64 /* SynchronizedOnType.swift */; }; + C84CC5581BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5571BDCF51200E06A64 /* SynchronizedSubscribeType.swift */; }; + C84CC5591BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5571BDCF51200E06A64 /* SynchronizedSubscribeType.swift */; }; + C84CC55A1BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5571BDCF51200E06A64 /* SynchronizedSubscribeType.swift */; }; + C84CC55B1BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5571BDCF51200E06A64 /* SynchronizedSubscribeType.swift */; }; + C84CC55D1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC55C1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift */; }; + C84CC55E1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC55C1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift */; }; + C84CC55F1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC55C1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift */; }; + C84CC5601BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC55C1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift */; }; + C84CC5621BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5611BDD037900E06A64 /* SynchronizedDisposeType.swift */; }; + C84CC5631BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5611BDD037900E06A64 /* SynchronizedDisposeType.swift */; }; + C84CC5641BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5611BDD037900E06A64 /* SynchronizedDisposeType.swift */; }; + C84CC5651BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5611BDD037900E06A64 /* SynchronizedDisposeType.swift */; }; + C84CC5671BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5661BDD08A500E06A64 /* SubscriptionDisposable.swift */; }; + C84CC5681BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5661BDD08A500E06A64 /* SubscriptionDisposable.swift */; }; + C84CC5691BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5661BDD08A500E06A64 /* SubscriptionDisposable.swift */; }; + C84CC56A1BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5661BDD08A500E06A64 /* SubscriptionDisposable.swift */; }; C86409FC1BA593F500D3C4E8 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86409FB1BA593F500D3C4E8 /* Range.swift */; }; C86409FD1BA593F500D3C4E8 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86409FB1BA593F500D3C4E8 /* Range.swift */; }; C8640A031BA5B12A00D3C4E8 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8640A021BA5B12A00D3C4E8 /* Repeat.swift */; }; @@ -936,6 +960,12 @@ C84B38E71BA43380001B7D88 /* ScheduledItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduledItem.swift; sourceTree = ""; }; C84B38ED1BA433CD001B7D88 /* Generate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Generate.swift; sourceTree = ""; }; C84CC53F1BDC3B3700E06A64 /* ElementAt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementAt.swift; sourceTree = ""; }; + C84CC54D1BDCF48200E06A64 /* LockOwnerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockOwnerType.swift; sourceTree = ""; }; + C84CC5521BDCF49300E06A64 /* SynchronizedOnType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedOnType.swift; sourceTree = ""; }; + C84CC5571BDCF51200E06A64 /* SynchronizedSubscribeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedSubscribeType.swift; sourceTree = ""; }; + C84CC55C1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedUnsubscribeType.swift; sourceTree = ""; }; + C84CC5611BDD037900E06A64 /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedDisposeType.swift; sourceTree = ""; }; + C84CC5661BDD08A500E06A64 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionDisposable.swift; sourceTree = ""; }; C86409FB1BA593F500D3C4E8 /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = ""; }; C8640A021BA5B12A00D3C4E8 /* Repeat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Repeat.swift; sourceTree = ""; }; C88253F11B8A752B00B02D69 /* RxCollectionViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCollectionViewReactiveArrayDataSource.swift; sourceTree = ""; }; @@ -1122,6 +1152,11 @@ children = ( C8093C4B1B8A72BE0088E94D /* AsyncLock.swift */, C8093C4C1B8A72BE0088E94D /* Lock.swift */, + C84CC54D1BDCF48200E06A64 /* LockOwnerType.swift */, + C84CC5521BDCF49300E06A64 /* SynchronizedOnType.swift */, + C84CC5571BDCF51200E06A64 /* SynchronizedSubscribeType.swift */, + C84CC55C1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift */, + C84CC5611BDD037900E06A64 /* SynchronizedDisposeType.swift */, ); path = Concurrency; sourceTree = ""; @@ -1144,6 +1179,7 @@ C8093C571B8A72BE0088E94D /* CompositeDisposable.swift */, C8093C581B8A72BE0088E94D /* DisposeBag.swift */, C8093C591B8A72BE0088E94D /* DisposeBase.swift */, + C84CC5661BDD08A500E06A64 /* SubscriptionDisposable.swift */, C8093C5A1B8A72BE0088E94D /* NAryDisposable.swift */, C8093C5B1B8A72BE0088E94D /* NAryDisposable.tt */, C8093C5C1B8A72BE0088E94D /* NopDisposable.swift */, @@ -2150,7 +2186,9 @@ C89CDB371BCB0DD7002063D9 /* ShareReplay1.swift in Sources */, C8093D2A1B8A72BE0088E94D /* ObserveOn.swift in Sources */, C8093D361B8A72BE0088E94D /* Sample.swift in Sources */, + C84CC54F1BDCF48200E06A64 /* LockOwnerType.swift in Sources */, D2752D621BC5551A0070C418 /* SkipUntil.swift in Sources */, + C84CC5541BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */, C8093CEA1B8A72BE0088E94D /* ScopedDisposable.swift in Sources */, C8093D261B8A72BE0088E94D /* Multicast.swift in Sources */, C8C3DA101B939767004D233E /* CurrentThreadScheduler.swift in Sources */, @@ -2165,6 +2203,7 @@ C8093D241B8A72BE0088E94D /* Merge.swift in Sources */, C8093D8E1B8A72BE0088E94D /* SchedulerType.swift in Sources */, C8093DA81B8A72BE0088E94D /* Variable.swift in Sources */, + C84CC5631BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */, C8093D961B8A72BE0088E94D /* OperationQueueScheduler.swift in Sources */, C8093D921B8A72BE0088E94D /* DispatchQueueSchedulerPriority.swift in Sources */, C8093D081B8A72BE0088E94D /* CombineLatest+arity.swift in Sources */, @@ -2197,6 +2236,7 @@ C8093D0E1B8A72BE0088E94D /* Concat.swift in Sources */, C8093CCA1B8A72BE0088E94D /* Lock.swift in Sources */, C8093D441B8A72BE0088E94D /* Take.swift in Sources */, + C84CC5591BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */, C8093D321B8A72BE0088E94D /* Reduce.swift in Sources */, C84B38EA1BA43380001B7D88 /* ScheduledItem.swift in Sources */, C8640A041BA5B12A00D3C4E8 /* Repeat.swift in Sources */, @@ -2214,10 +2254,12 @@ C8093D401B8A72BE0088E94D /* SubscribeOn.swift in Sources */, CBEE77201BD649A000AD584C /* ToArray.swift in Sources */, C8093CFE1B8A72BE0088E94D /* Observable.swift in Sources */, + C84CC55E1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */, C8093CE21B8A72BE0088E94D /* NAryDisposable.swift in Sources */, C8093CEC1B8A72BE0088E94D /* SerialDisposable.swift in Sources */, C8C3DA0D1B93959F004D233E /* Never.swift in Sources */, C8093D7C1B8A72BE0088E94D /* ObserverType+Extensions.swift in Sources */, + C84CC5681BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */, C8093CF61B8A72BE0088E94D /* Event.swift in Sources */, C8093D521B8A72BE0088E94D /* Zip.swift in Sources */, ); @@ -2272,7 +2314,9 @@ C89CDB361BCB0DD7002063D9 /* ShareReplay1.swift in Sources */, C8093D291B8A72BE0088E94D /* ObserveOn.swift in Sources */, C8093D351B8A72BE0088E94D /* Sample.swift in Sources */, + C84CC54E1BDCF48200E06A64 /* LockOwnerType.swift in Sources */, D285BAC41BC0231000B3F602 /* SkipUntil.swift in Sources */, + C84CC5531BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */, C8093CE91B8A72BE0088E94D /* ScopedDisposable.swift in Sources */, C8093D251B8A72BE0088E94D /* Multicast.swift in Sources */, C8C3DA0F1B939767004D233E /* CurrentThreadScheduler.swift in Sources */, @@ -2287,6 +2331,7 @@ C8093D231B8A72BE0088E94D /* Merge.swift in Sources */, C8093D8D1B8A72BE0088E94D /* SchedulerType.swift in Sources */, C8093DA71B8A72BE0088E94D /* Variable.swift in Sources */, + C84CC5621BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */, C8093D951B8A72BE0088E94D /* OperationQueueScheduler.swift in Sources */, C8093D911B8A72BE0088E94D /* DispatchQueueSchedulerPriority.swift in Sources */, C8093D071B8A72BE0088E94D /* CombineLatest+arity.swift in Sources */, @@ -2319,6 +2364,7 @@ C8093D0D1B8A72BE0088E94D /* Concat.swift in Sources */, C8093CC91B8A72BE0088E94D /* Lock.swift in Sources */, C8093D431B8A72BE0088E94D /* Take.swift in Sources */, + C84CC5581BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */, C8093D311B8A72BE0088E94D /* Reduce.swift in Sources */, C84B38E91BA43380001B7D88 /* ScheduledItem.swift in Sources */, C8640A031BA5B12A00D3C4E8 /* Repeat.swift in Sources */, @@ -2336,10 +2382,12 @@ C8093D3F1B8A72BE0088E94D /* SubscribeOn.swift in Sources */, CBEE771F1BD649A000AD584C /* ToArray.swift in Sources */, C8093CFD1B8A72BE0088E94D /* Observable.swift in Sources */, + C84CC55D1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */, C8093CE11B8A72BE0088E94D /* NAryDisposable.swift in Sources */, C8093CEB1B8A72BE0088E94D /* SerialDisposable.swift in Sources */, C8C3DA0C1B93959F004D233E /* Never.swift in Sources */, C8093D7B1B8A72BE0088E94D /* ObserverType+Extensions.swift in Sources */, + C84CC5671BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */, C8093CF51B8A72BE0088E94D /* Event.swift in Sources */, C8093D511B8A72BE0088E94D /* Zip.swift in Sources */, ); @@ -2394,7 +2442,9 @@ C89CDB391BCB0DD7002063D9 /* ShareReplay1.swift in Sources */, C8F0BFB71BBBFB8B001B112F /* ObserveOn.swift in Sources */, C8F0BFB81BBBFB8B001B112F /* Sample.swift in Sources */, + C84CC5511BDCF48200E06A64 /* LockOwnerType.swift in Sources */, D21C29311BC6A1C300448E70 /* SkipUntil.swift in Sources */, + C84CC5561BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */, C8F0BFB91BBBFB8B001B112F /* ScopedDisposable.swift in Sources */, C8F0BFBA1BBBFB8B001B112F /* Multicast.swift in Sources */, C8F0BFBB1BBBFB8B001B112F /* CurrentThreadScheduler.swift in Sources */, @@ -2409,6 +2459,7 @@ C8F0BFC31BBBFB8B001B112F /* Merge.swift in Sources */, C8F0BFC41BBBFB8B001B112F /* SchedulerType.swift in Sources */, C8F0BFC51BBBFB8B001B112F /* Variable.swift in Sources */, + C84CC5651BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */, C8F0BFC61BBBFB8B001B112F /* OperationQueueScheduler.swift in Sources */, C8F0BFC71BBBFB8B001B112F /* DispatchQueueSchedulerPriority.swift in Sources */, C8F0BFC81BBBFB8B001B112F /* CombineLatest+arity.swift in Sources */, @@ -2441,6 +2492,7 @@ C8F0BFE21BBBFB8B001B112F /* Concat.swift in Sources */, C8F0BFE31BBBFB8B001B112F /* Lock.swift in Sources */, C8F0BFE41BBBFB8B001B112F /* Take.swift in Sources */, + C84CC55B1BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */, C8F0BFE51BBBFB8B001B112F /* Reduce.swift in Sources */, C8F0BFE61BBBFB8B001B112F /* ScheduledItem.swift in Sources */, C8F0BFE71BBBFB8B001B112F /* Repeat.swift in Sources */, @@ -2458,10 +2510,12 @@ C8F0BFF31BBBFB8B001B112F /* SubscribeOn.swift in Sources */, CBEE77221BD649A000AD584C /* ToArray.swift in Sources */, C8F0BFF41BBBFB8B001B112F /* Observable.swift in Sources */, + C84CC5601BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */, C8F0BFF51BBBFB8B001B112F /* NAryDisposable.swift in Sources */, C8F0BFF61BBBFB8B001B112F /* SerialDisposable.swift in Sources */, C8F0BFF71BBBFB8B001B112F /* Never.swift in Sources */, C8F0BFF81BBBFB8B001B112F /* ObserverType+Extensions.swift in Sources */, + C84CC56A1BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */, C8F0BFF91BBBFB8B001B112F /* Event.swift in Sources */, C8F0BFFA1BBBFB8B001B112F /* Zip.swift in Sources */, ); @@ -2666,7 +2720,9 @@ D2EBEB2A1BB9B6C5003A27DC /* Zip+CollectionType.swift in Sources */, C89CDB381BCB0DD7002063D9 /* ShareReplay1.swift in Sources */, D2EBEB401BB9B6DE003A27DC /* BehaviorSubject.swift in Sources */, + C84CC5501BDCF48200E06A64 /* LockOwnerType.swift in Sources */, D2EBEB271BB9B6C1003A27DC /* Timer.swift in Sources */, + C84CC5551BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */, D2752D631BC5551B0070C418 /* SkipUntil.swift in Sources */, D2EBEB351BB9B6D2003A27DC /* ObserverBase.swift in Sources */, D2EBEB0F1BB9B6C1003A27DC /* Generate.swift in Sources */, @@ -2681,6 +2737,7 @@ D2EBEAFB1BB9B6B2003A27DC /* StableCompositeDisposable.swift in Sources */, D2EBEB011BB9B6BA003A27DC /* CombineLatest.swift in Sources */, D2EBEB021BB9B6BA003A27DC /* CombineLatest+arity.swift in Sources */, + C84CC5641BDD037900E06A64 /* SynchronizedDisposeType.swift in Sources */, D2EBEB211BB9B6C1003A27DC /* SubscribeOn.swift in Sources */, D2EBEB251BB9B6C1003A27DC /* TakeWhile.swift in Sources */, D2EBEB221BB9B6C1003A27DC /* Switch.swift in Sources */, @@ -2713,6 +2770,7 @@ D2EBEB2B1BB9B6CA003A27DC /* Observable+Aggregate.swift in Sources */, D2EBEB291BB9B6C1003A27DC /* Zip+arity.swift in Sources */, D2EBEB241BB9B6C1003A27DC /* TakeUntil.swift in Sources */, + C84CC55A1BDCF51200E06A64 /* SynchronizedSubscribeType.swift in Sources */, D2EBEB3B1BB9B6D8003A27DC /* OperationQueueScheduler.swift in Sources */, D2EBEAE51BB9B697003A27DC /* AnyObserver.swift in Sources */, D2EBEB3D1BB9B6D8003A27DC /* SchedulerServices+Emulation.swift in Sources */, @@ -2730,10 +2788,12 @@ D2EBEAF41BB9B6AE003A27DC /* DisposeBase.swift in Sources */, CBEE77211BD649A000AD584C /* ToArray.swift in Sources */, D2EBEB3F1BB9B6D8003A27DC /* CurrentThreadScheduler.swift in Sources */, + C84CC55F1BDD010800E06A64 /* SynchronizedUnsubscribeType.swift in Sources */, D2EBEAF21BB9B6AE003A27DC /* CompositeDisposable.swift in Sources */, D2EBEB0E1BB9B6C1003A27DC /* FlatMap.swift in Sources */, D2EBEB171BB9B6C1003A27DC /* Producer.swift in Sources */, D2EBEAF91BB9B6B2003A27DC /* SerialDisposable.swift in Sources */, + C84CC5691BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */, D2EBEB0A1BB9B6C1003A27DC /* Do.swift in Sources */, D2EBEB2E1BB9B6CA003A27DC /* Observable+Creation.swift in Sources */, ); diff --git a/RxExample/RxExample.xcodeproj/project.pbxproj b/RxExample/RxExample.xcodeproj/project.pbxproj index 580da957..02b11de6 100644 --- a/RxExample/RxExample.xcodeproj/project.pbxproj +++ b/RxExample/RxExample.xcodeproj/project.pbxproj @@ -113,6 +113,13 @@ C84B913C1B8A282000C9CCCF /* RxCollectionViewSectionedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C859B9A71B45C83700D012D7 /* RxCollectionViewSectionedDataSource.swift */; }; C84B913D1B8A282000C9CCCF /* RxCollectionViewSectionedAnimatedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C859B9A91B45CB0900D012D7 /* RxCollectionViewSectionedAnimatedDataSource.swift */; }; C84CC52E1BDC344100E06A64 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC52D1BDC344100E06A64 /* ElementAt.swift */; }; + C84CC58B1BDD486300E06A64 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC56B1BDD08F500E06A64 /* LockOwnerType.swift */; }; + C84CC58C1BDD486300E06A64 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC56C1BDD08F500E06A64 /* SynchronizedDisposeType.swift */; }; + C84CC58D1BDD486300E06A64 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC56D1BDD08F500E06A64 /* SynchronizedOnType.swift */; }; + C84CC58E1BDD486300E06A64 /* SynchronizedSubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC56E1BDD08F500E06A64 /* SynchronizedSubscribeType.swift */; }; + C84CC58F1BDD486300E06A64 /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC56F1BDD08F500E06A64 /* SynchronizedUnsubscribeType.swift */; }; + C84CC5901BDD486300E06A64 /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C894642A1BC6C2B00055219D /* AsyncLock.swift */; }; + C84CC5911BDD48B800E06A64 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84CC5831BDD484400E06A64 /* SubscriptionDisposable.swift */; }; C859B9A41B45C5D900D012D7 /* PartialUpdatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C859B9A31B45C5D900D012D7 /* PartialUpdatesViewController.swift */; }; C859B9AC1B45CF9100D012D7 /* NumberCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C859B9AB1B45CF9100D012D7 /* NumberCell.swift */; }; C859B9AE1B45CFAB00D012D7 /* NumberSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C859B9AD1B45CFAB00D012D7 /* NumberSectionView.swift */; }; @@ -140,7 +147,6 @@ C890A65A1AEBD28A00AFF7E6 /* GitHubAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C890A6591AEBD28A00AFF7E6 /* GitHubAPI.swift */; }; C890A65D1AEC084100AFF7E6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C890A65C1AEC084100AFF7E6 /* ViewController.swift */; }; C894649E1BC6C2B00055219D /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89464281BC6C2B00055219D /* Cancelable.swift */; }; - C894649F1BC6C2B00055219D /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C894642A1BC6C2B00055219D /* AsyncLock.swift */; }; C89464A01BC6C2B00055219D /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C894642B1BC6C2B00055219D /* Lock.swift */; }; C89464A11BC6C2B00055219D /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C894642C1BC6C2B00055219D /* ConnectableObservableType.swift */; }; C89464A21BC6C2B00055219D /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = C894642E1BC6C2B00055219D /* Bag.swift */; }; @@ -501,6 +507,12 @@ C83367111AD029AE00C668A7 /* HtmlParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlParsing.swift; sourceTree = ""; }; C83367121AD029AE00C668A7 /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; C84CC52D1BDC344100E06A64 /* ElementAt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementAt.swift; sourceTree = ""; }; + C84CC56B1BDD08F500E06A64 /* LockOwnerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockOwnerType.swift; sourceTree = ""; }; + C84CC56C1BDD08F500E06A64 /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedDisposeType.swift; sourceTree = ""; }; + C84CC56D1BDD08F500E06A64 /* SynchronizedOnType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedOnType.swift; sourceTree = ""; }; + C84CC56E1BDD08F500E06A64 /* SynchronizedSubscribeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedSubscribeType.swift; sourceTree = ""; }; + C84CC56F1BDD08F500E06A64 /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedUnsubscribeType.swift; sourceTree = ""; }; + C84CC5831BDD484400E06A64 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionDisposable.swift; sourceTree = ""; }; C859B9A31B45C5D900D012D7 /* PartialUpdatesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PartialUpdatesViewController.swift; sourceTree = ""; }; C859B9A51B45C80700D012D7 /* RxCollectionViewSectionedReloadDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCollectionViewSectionedReloadDataSource.swift; sourceTree = ""; }; C859B9A71B45C83700D012D7 /* RxCollectionViewSectionedDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCollectionViewSectionedDataSource.swift; sourceTree = ""; }; @@ -1066,6 +1078,11 @@ C89464291BC6C2B00055219D /* Concurrency */ = { isa = PBXGroup; children = ( + C84CC56B1BDD08F500E06A64 /* LockOwnerType.swift */, + C84CC56C1BDD08F500E06A64 /* SynchronizedDisposeType.swift */, + C84CC56D1BDD08F500E06A64 /* SynchronizedOnType.swift */, + C84CC56E1BDD08F500E06A64 /* SynchronizedSubscribeType.swift */, + C84CC56F1BDD08F500E06A64 /* SynchronizedUnsubscribeType.swift */, C894642A1BC6C2B00055219D /* AsyncLock.swift */, C894642B1BC6C2B00055219D /* Lock.swift */, ); @@ -1085,6 +1102,7 @@ C89464321BC6C2B00055219D /* Disposables */ = { isa = PBXGroup; children = ( + C84CC5831BDD484400E06A64 /* SubscriptionDisposable.swift */, C89464331BC6C2B00055219D /* AnonymousDisposable.swift */, C89464341BC6C2B00055219D /* BinaryDisposable.swift */, C89464351BC6C2B00055219D /* CompositeDisposable.swift */, @@ -1644,6 +1662,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C84CC58B1BDD486300E06A64 /* LockOwnerType.swift in Sources */, C89465971BC6C2BC0055219D /* UIScrollView+Rx.swift in Sources */, C8297E2F1B6CF905000589EA /* RxTableViewSectionedAnimatedDataSource.swift in Sources */, C89464FF1BC6C2B00055219D /* DispatchQueueSchedulerPriority.swift in Sources */, @@ -1661,6 +1680,7 @@ C89465731BC6C2BC0055219D /* Deallocating.swift in Sources */, C89464A51BC6C2B00055219D /* Disposable.swift in Sources */, C89464F91BC6C2B00055219D /* ObserverType+Extensions.swift in Sources */, + C84CC58D1BDD486300E06A64 /* SynchronizedOnType.swift in Sources */, C89464DC1BC6C2B00055219D /* Scan.swift in Sources */, C89464B21BC6C2B00055219D /* StableCompositeDisposable.swift in Sources */, C89464AE1BC6C2B00055219D /* ScheduledDisposable.swift in Sources */, @@ -1681,6 +1701,7 @@ C89465961BC6C2BC0055219D /* UILabel+Rx.swift in Sources */, C894659C1BC6C2BC0055219D /* UISwitch+Rx.swift in Sources */, C89464F81BC6C2B00055219D /* TailRecursiveSink.swift in Sources */, + C84CC58C1BDD486300E06A64 /* SynchronizedDisposeType.swift in Sources */, C89464BF1BC6C2B00055219D /* CombineLatest+arity.swift in Sources */, C89465751BC6C2BC0055219D /* KVOObservable.swift in Sources */, C89464CB1BC6C2B00055219D /* FailWith.swift in Sources */, @@ -1761,10 +1782,12 @@ C8297E3F1B6CF905000589EA /* SectionModelType.swift in Sources */, C8297E401B6CF905000589EA /* ImageService.swift in Sources */, C89464AD1BC6C2B00055219D /* NopDisposable.swift in Sources */, + C84CC5901BDD486300E06A64 /* AsyncLock.swift in Sources */, CBEE77541BD8C7B700AD584C /* ToArray.swift in Sources */, C89465771BC6C2BC0055219D /* NSNotificationCenter+Rx.swift in Sources */, C89465091BC6C2B00055219D /* ReplaySubject.swift in Sources */, C8297E411B6CF905000589EA /* RxCollectionViewSectionedReloadDataSource.swift in Sources */, + C84CC58E1BDD486300E06A64 /* SynchronizedSubscribeType.swift in Sources */, C89464A81BC6C2B00055219D /* CompositeDisposable.swift in Sources */, C89464D21BC6C2B00055219D /* Multicast.swift in Sources */, C89465821BC6C2BC0055219D /* RxCollectionViewDataSourceType.swift in Sources */, @@ -1808,6 +1831,7 @@ C89464E31BC6C2B00055219D /* TakeUntil.swift in Sources */, C89464FB1BC6C2B00055219D /* Rx.swift in Sources */, C89464FD1BC6C2B00055219D /* ConcurrentDispatchQueueScheduler.swift in Sources */, + C84CC5911BDD48B800E06A64 /* SubscriptionDisposable.swift in Sources */, C89464C71BC6C2B00055219D /* DelaySubscription.swift in Sources */, C8297E481B6CF905000589EA /* Differentiator.swift in Sources */, C8297E491B6CF905000589EA /* WikipediaSearchCell.swift in Sources */, @@ -1820,6 +1844,7 @@ C89464D31BC6C2B00055219D /* Never.swift in Sources */, C8297E4D1B6CF905000589EA /* RxTableViewSectionedReloadDataSource.swift in Sources */, C89465931BC6C2BC0055219D /* UIDatePicker+Rx.swift in Sources */, + C84CC58F1BDD486300E06A64 /* SynchronizedUnsubscribeType.swift in Sources */, C8297E4E1B6CF905000589EA /* RxCollectionViewSectionedAnimatedDataSource.swift in Sources */, C89CDB711BCC45E5002063D9 /* ShareReplay1.swift in Sources */, C89464BD1BC6C2B00055219D /* Buffer.swift in Sources */, @@ -1838,7 +1863,6 @@ D2AF91981BD3D95900A008C1 /* Using.swift in Sources */, C8297E501B6CF905000589EA /* TableViewController.swift in Sources */, C8297E511B6CF905000589EA /* PartialUpdatesViewController.swift in Sources */, - C894649F1BC6C2B00055219D /* AsyncLock.swift in Sources */, C8B145141BD2E4D000267DCE /* ConcurrentMainScheduler.swift in Sources */, C8297E521B6CF905000589EA /* Dependencies.swift in Sources */, C80DDED91BCE9046006A1832 /* ObservableConvertibleType+Driver.swift in Sources */, diff --git a/RxSwift/Concurrency/Lock.swift b/RxSwift/Concurrency/Lock.swift index 5ec4a06d..df4d6f40 100644 --- a/RxSwift/Concurrency/Lock.swift +++ b/RxSwift/Concurrency/Lock.swift @@ -8,6 +8,11 @@ import Foundation +protocol Lock { + func lock() + func unlock() +} + /** Simple wrapper for spin lock. */ @@ -49,7 +54,7 @@ struct SpinLock { } } -extension NSRecursiveLock { +extension NSRecursiveLock : Lock { func performLocked(@noescape action: () -> Void) { self.lock() action() diff --git a/RxSwift/Concurrency/LockOwnerType.swift b/RxSwift/Concurrency/LockOwnerType.swift new file mode 100644 index 00000000..b11fcaa8 --- /dev/null +++ b/RxSwift/Concurrency/LockOwnerType.swift @@ -0,0 +1,23 @@ +// +// LockOwnerType.swift +// Rx +// +// Created by Krunoslav Zaher on 10/25/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +protocol LockOwnerType : class, Lock { + var _lock: NSRecursiveLock { get } +} + +extension LockOwnerType { + func lock() { + _lock.lock() + } + + func unlock() { + _lock.unlock() + } +} \ No newline at end of file diff --git a/RxSwift/Concurrency/SynchronizedDisposeType.swift b/RxSwift/Concurrency/SynchronizedDisposeType.swift new file mode 100644 index 00000000..5764575e --- /dev/null +++ b/RxSwift/Concurrency/SynchronizedDisposeType.swift @@ -0,0 +1,20 @@ +// +// SynchronizedDisposeType.swift +// Rx +// +// Created by Krunoslav Zaher on 10/25/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +protocol SynchronizedDisposeType : class, Disposable, Lock { + func _synchronized_dispose() +} + +extension SynchronizedDisposeType { + func synchronizedDispose() { + lock(); defer { unlock() } + _synchronized_dispose() + } +} \ No newline at end of file diff --git a/RxSwift/Concurrency/SynchronizedOnType.swift b/RxSwift/Concurrency/SynchronizedOnType.swift new file mode 100644 index 00000000..84a3df5d --- /dev/null +++ b/RxSwift/Concurrency/SynchronizedOnType.swift @@ -0,0 +1,20 @@ +// +// SynchronizedOnType.swift +// Rx +// +// Created by Krunoslav Zaher on 10/25/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +protocol SynchronizedOnType : class, ObserverType, Lock { + func _synchronized_on(event: Event) +} + +extension SynchronizedOnType { + func synchronizedOn(event: Event) { + lock(); defer { unlock() } + _synchronized_on(event) + } +} \ No newline at end of file diff --git a/RxSwift/Concurrency/SynchronizedSubscribeType.swift b/RxSwift/Concurrency/SynchronizedSubscribeType.swift new file mode 100644 index 00000000..a4903157 --- /dev/null +++ b/RxSwift/Concurrency/SynchronizedSubscribeType.swift @@ -0,0 +1,20 @@ +// +// SynchronizedSubscribeType.swift +// Rx +// +// Created by Krunoslav Zaher on 10/25/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +protocol SynchronizedSubscribeType : class, ObservableType, Lock { + func _synchronized_subscribe(observer: O) -> Disposable +} + +extension SynchronizedSubscribeType { + func synchronizedSubscribe(observer: O) -> Disposable { + lock(); defer { unlock() } + return _synchronized_subscribe(observer) + } +} \ No newline at end of file diff --git a/RxSwift/Concurrency/SynchronizedUnsubscribeType.swift b/RxSwift/Concurrency/SynchronizedUnsubscribeType.swift new file mode 100644 index 00000000..a73f8fca --- /dev/null +++ b/RxSwift/Concurrency/SynchronizedUnsubscribeType.swift @@ -0,0 +1,22 @@ +// +// SynchronizedUnsubscribeType.swift +// Rx +// +// Created by Krunoslav Zaher on 10/25/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +protocol SynchronizedUnsubscribeType : class, Lock { + typealias DisposeKey + + func _synchronized_unsubscribe(disposeKey: DisposeKey) +} + +extension SynchronizedUnsubscribeType { + func synchronizedUnsubscribe(disposeKey: DisposeKey) { + lock(); defer { unlock() } + _synchronized_unsubscribe(disposeKey) + } +} \ No newline at end of file diff --git a/RxSwift/DataStructures/Bag.swift b/RxSwift/DataStructures/Bag.swift index e9023b69..72968fe4 100644 --- a/RxSwift/DataStructures/Bag.swift +++ b/RxSwift/DataStructures/Bag.swift @@ -53,7 +53,7 @@ public struct Bag : CustomStringConvertible { private var _uniqueIdentity: Identity? private var _nextKey: ScopeUniqueTokenType = 0 - private var _pairs = [Entry]() + var _pairs = ContiguousArray() /** Creates new empty `Bag`. diff --git a/RxSwift/Disposables/SubscriptionDisposable.swift b/RxSwift/Disposables/SubscriptionDisposable.swift new file mode 100644 index 00000000..7a3e1e97 --- /dev/null +++ b/RxSwift/Disposables/SubscriptionDisposable.swift @@ -0,0 +1,23 @@ +// +// SubscriptionDisposable.swift +// Rx +// +// Created by Krunoslav Zaher on 10/25/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +struct SubscriptionDisposable : Disposable { + private let _key: T.DisposeKey + private weak var _owner: T? + + init(owner: T, key: T.DisposeKey) { + _owner = owner + _key = key + } + + func dispose() { + _owner?.synchronizedUnsubscribe(_key) + } +} \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/CombineLatest.swift b/RxSwift/Observables/Implementations/CombineLatest.swift index 40926eff..300cf2db 100644 --- a/RxSwift/Observables/Implementations/CombineLatest.swift +++ b/RxSwift/Observables/Implementations/CombineLatest.swift @@ -90,13 +90,16 @@ class CombineLatestSink : Sink, CombineLatestProtocol { } } -class CombineLatestObserver : ObserverType { +class CombineLatestObserver + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias Element = ElementType typealias ValueSetter = (Element) -> Void private let _parent: CombineLatestProtocol - private let _lock: NSRecursiveLock + let _lock: NSRecursiveLock private let _index: Int private let _this: Disposable private let _setLatestValue: ValueSetter @@ -110,18 +113,20 @@ class CombineLatestObserver : ObserverType { } func on(event: Event) { - _lock.performLocked { - switch event { - case .Next(let value): - _setLatestValue(value) - _parent.next(_index) - case .Error(let error): - _this.dispose() - _parent.fail(error) - case .Completed: - _this.dispose() - _parent.done(_index) - } + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next(let value): + _setLatestValue(value) + _parent.next(_index) + case .Error(let error): + _this.dispose() + _parent.fail(error) + case .Completed: + _this.dispose() + _parent.done(_index) } } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/ShareReplay1.swift b/RxSwift/Observables/Implementations/ShareReplay1.swift index 9ae0accd..ba478eea 100644 --- a/RxSwift/Observables/Implementations/ShareReplay1.swift +++ b/RxSwift/Observables/Implementations/ShareReplay1.swift @@ -9,10 +9,19 @@ import Foundation // optimized version of share replay for most common case -class ShareReplay1 : Observable, ObserverType { +class ShareReplay1 + : Observable + , ObserverType + , LockOwnerType + , SynchronizedOnType + , SynchronizedSubscribeType + , SynchronizedUnsubscribeType { + + typealias DisposeKey = Bag>.KeyType + private let _source: Observable - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() private var _subscription: Disposable? private var _element: Element? @@ -23,55 +32,61 @@ class ShareReplay1 : Observable, ObserverType { self._source = source } + override func subscribe(observer: O) -> Disposable { - return _lock.calculateLocked { - if let element = self._element { - observer.on(.Next(element)) - } + return synchronizedSubscribe(observer) + } - if let stopEvent = self._stopEvent { - observer.on(stopEvent) - return NopDisposable.instance - } + func _synchronized_subscribe(observer: O) -> Disposable { + if let element = self._element { + observer.on(.Next(element)) + } - let initialCount = self._observers.count + if let stopEvent = self._stopEvent { + observer.on(stopEvent) + return NopDisposable.instance + } - let observerKey = self._observers.insert(AnyObserver(observer)) + let initialCount = self._observers.count - if initialCount == 0 { - self._subscription = self._source.subscribe(self) - } + let disposeKey = self._observers.insert(AnyObserver(observer)) - return AnonymousDisposable { - self._lock.performLocked { - self._observers.removeKey(observerKey) + if initialCount == 0 { + self._subscription = self._source.subscribe(self) + } - if self._observers.count == 0 { - self._subscription?.dispose() - self._subscription = nil - } - } - } + return SubscriptionDisposable(owner: self, key: disposeKey) + } + + func _synchronized_unsubscribe(disposeKey: DisposeKey) { + // if already unsubscribed, just return + if self._observers.removeKey(disposeKey) == nil { + return + } + + if self._observers.count == 0 { + self._subscription?.dispose() + self._subscription = nil } } func on(event: Event) { - _lock.performLocked { - if self._stopEvent != nil { - return - } + synchronizedOn(event) + } - if case .Next(let element) = event { - self._element = element - } - - if event.isStopEvent { - self._stopEvent = event - } - - _observers.forEach { o in - o.on(event) - } + func _synchronized_on(event: Event) { + if self._stopEvent != nil { + return } + + if case .Next(let element) = event { + self._element = element + } + + if event.isStopEvent { + self._stopEvent = event + } + + _observers.on(event) } } \ No newline at end of file diff --git a/RxSwift/Schedulers/CurrentThreadScheduler.swift b/RxSwift/Schedulers/CurrentThreadScheduler.swift index 89779860..b839a4a8 100644 --- a/RxSwift/Schedulers/CurrentThreadScheduler.swift +++ b/RxSwift/Schedulers/CurrentThreadScheduler.swift @@ -9,6 +9,7 @@ import Foundation let CurrentThreadSchedulerKeyInstance = CurrentThreadSchedulerKey() +let CurrentThreadSchedulerQueueKeyInstance = CurrentThreadSchedulerQueueKey() class CurrentThreadSchedulerKey : NSObject, NSCopying { override func isEqual(object: AnyObject?) -> Bool { @@ -26,6 +27,22 @@ class CurrentThreadSchedulerKey : NSObject, NSCopying { } } +class CurrentThreadSchedulerQueueKey : NSObject, NSCopying { + override func isEqual(object: AnyObject?) -> Bool { + return object === CurrentThreadSchedulerQueueKeyInstance + } + + override var hashValue: Int { return -904739207 } + + override func copy() -> AnyObject { + return CurrentThreadSchedulerQueueKeyInstance + } + + func copyWithZone(zone: NSZone) -> AnyObject { + return CurrentThreadSchedulerQueueKeyInstance + } +} + /** Represents an object that schedules units of work on the current thread. @@ -43,15 +60,15 @@ public class CurrentThreadScheduler : ImmediateSchedulerType { static var queue : ScheduleQueue? { get { - return NSThread.currentThread().threadDictionary[CurrentThreadSchedulerKeyInstance] as? ScheduleQueue + return NSThread.currentThread().threadDictionary[CurrentThreadSchedulerQueueKeyInstance] as? ScheduleQueue } set { let threadDictionary = NSThread.currentThread().threadDictionary if let newValue = newValue { - threadDictionary[CurrentThreadSchedulerKeyInstance] = newValue + threadDictionary[CurrentThreadSchedulerQueueKeyInstance] = newValue } else { - threadDictionary.removeObjectForKey(CurrentThreadSchedulerKeyInstance) + threadDictionary.removeObjectForKey(CurrentThreadSchedulerQueueKeyInstance) } } } @@ -59,8 +76,18 @@ public class CurrentThreadScheduler : ImmediateSchedulerType { /** Gets a value that indicates whether the caller must call a `schedule` method. */ - public static var isScheduleRequired: Bool { - return NSThread.currentThread().threadDictionary[CurrentThreadSchedulerKeyInstance] == nil + public static private(set) var isScheduleRequired: Bool { + get { + return NSThread.currentThread().threadDictionary[CurrentThreadSchedulerKeyInstance] == nil + } + set(value) { + if value { + NSThread.currentThread().threadDictionary.removeObjectForKey(CurrentThreadSchedulerKeyInstance) + } + else { + NSThread.currentThread().threadDictionary[CurrentThreadSchedulerKeyInstance] = CurrentThreadSchedulerKeyInstance + } + } } /** @@ -74,28 +101,43 @@ public class CurrentThreadScheduler : ImmediateSchedulerType { - returns: The disposable object used to cancel the scheduled action (best effort). */ public func schedule(state: StateType, action: (StateType) -> Disposable) -> Disposable { - let queue = CurrentThreadScheduler.queue - - if let queue = queue { - let scheduledItem = ScheduledItem(action: action, state: state, time: 0) - queue.value.enqueue(scheduledItem) - return scheduledItem - } - - let newQueue = RxMutableBox(Queue(capacity: 0)) - CurrentThreadScheduler.queue = newQueue - - action(state) - - while let latest = newQueue.value.tryDequeue() { - if latest.disposed { - continue + if CurrentThreadScheduler.isScheduleRequired { + CurrentThreadScheduler.isScheduleRequired = false + + action(state) + + defer { + CurrentThreadScheduler.isScheduleRequired = true + CurrentThreadScheduler.queue = nil } - latest.invoke() + + guard let queue = CurrentThreadScheduler.queue else { + return NopDisposable.instance + } + + while let latest = queue.value.tryDequeue() { + if latest.disposed { + continue + } + latest.invoke() + } + + return NopDisposable.instance } - - CurrentThreadScheduler.queue = nil - - return NopDisposable.instance + + let existingQueue = CurrentThreadScheduler.queue + + let queue: RxMutableBox> + if let existingQueue = existingQueue { + queue = existingQueue + } + else { + queue = RxMutableBox(Queue(capacity: 1)) + CurrentThreadScheduler.queue = queue + } + + let scheduledItem = ScheduledItem(action: action, state: state, time: 0) + queue.value.enqueue(scheduledItem) + return scheduledItem } } \ No newline at end of file diff --git a/RxSwift/Subjects/BehaviorSubject.swift b/RxSwift/Subjects/BehaviorSubject.swift index 74ffb6e6..7623332d 100644 --- a/RxSwift/Subjects/BehaviorSubject.swift +++ b/RxSwift/Subjects/BehaviorSubject.swift @@ -103,7 +103,7 @@ public final class BehaviorSubject : Observable, SubjectType, _stoppedEvent = event } - _observers.forEach { $0.on(event) } + _observers.on(event) } } diff --git a/RxSwift/Subjects/PublishSubject.swift b/RxSwift/Subjects/PublishSubject.swift index 52909ed5..fd1d5712 100644 --- a/RxSwift/Subjects/PublishSubject.swift +++ b/RxSwift/Subjects/PublishSubject.swift @@ -8,46 +8,26 @@ import Foundation -class Subscription : Disposable { - typealias KeyType = Bag>.KeyType - - private var _lock = SpinLock() - - // state - private var _subject: PublishSubject? - private var _key: KeyType? - - init(subject: PublishSubject, key: KeyType) { - _key = key - _subject = subject - } - - func dispose() { - _lock.performLocked { - guard let subject = _subject, - let key = _key else { - return - } - - _subject = nil - _key = nil - - subject.unsubscribe(key) - } - } -} - /** Represents an object that is both an observable sequence as well as an observer. Each notification is broadcasted to all subscribed observers. */ -public class PublishSubject : Observable, SubjectType, Cancelable, ObserverType { +public class PublishSubject + : Observable + , SubjectType + , Cancelable + , ObserverType + , LockOwnerType + , SynchronizedOnType + , SynchronizedSubscribeType + , SynchronizedUnsubscribeType + , SynchronizedDisposeType { public typealias SubjectObserverType = PublishSubject typealias DisposeKey = Bag>.KeyType - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _disposed = false @@ -59,9 +39,7 @@ public class PublishSubject : Observable, SubjectType, Cancela */ public var disposed: Bool { get { - return _lock.calculateLocked { - return _disposed - } + return _disposed } } @@ -78,20 +56,22 @@ public class PublishSubject : Observable, SubjectType, Cancela - parameter event: Event to send to the observers. */ public func on(event: Event) { - _lock.performLocked { - switch event { - case .Next(_): - if disposed || _stoppedEvent != nil { - return - } - - _observers.forEach { $0.on(event) } - case .Completed, .Error: - if _stoppedEvent == nil { - _stoppedEvent = event - _observers.forEach { $0.on(event) } - _observers.removeAll() - } + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next(_): + if _disposed || _stoppedEvent != nil { + return + } + + _observers.on(event) + case .Completed, .Error: + if _stoppedEvent == nil { + _stoppedEvent = event + _observers.on(event) + _observers.removeAll() } } } @@ -103,26 +83,27 @@ public class PublishSubject : Observable, SubjectType, Cancela - returns: Disposable object that can be used to unsubscribe the observer from the subject. */ public override func subscribe(observer: O) -> Disposable { - return _lock.calculateLocked { - if let stoppedEvent = _stoppedEvent { - observer.on(stoppedEvent) - return NopDisposable.instance - } - - if disposed { - observer.on(.Error(RxError.DisposedError)) - return NopDisposable.instance - } - - let key = _observers.insert(observer.asObserver()) - return Subscription(subject: self, key: key) - } + return synchronizedSubscribe(observer) } - func unsubscribe(key: DisposeKey) { - _lock.performLocked { - _ = _observers.removeKey(key) + func _synchronized_subscribe(observer: O) -> Disposable { + if let stoppedEvent = _stoppedEvent { + observer.on(stoppedEvent) + return NopDisposable.instance } + + if _disposed { + observer.on(.Error(RxError.DisposedError)) + return NopDisposable.instance + } + + let key = _observers.insert(observer.asObserver()) + return SubscriptionDisposable(owner: self, key: key) + } + + + func _synchronized_unsubscribe(disposeKey: DisposeKey) { + _ = _observers.removeKey(disposeKey) } /** @@ -136,10 +117,12 @@ public class PublishSubject : Observable, SubjectType, Cancela Unsubscribe all observers and release resources. */ public func dispose() { - _lock.performLocked { - _disposed = true - _observers.removeAll() - _stoppedEvent = nil - } + synchronizedDispose() + } + + func _synchronized_dispose() { + _disposed = true + _observers.removeAll() + _stoppedEvent = nil } } \ No newline at end of file diff --git a/RxSwift/Subjects/ReplaySubject.swift b/RxSwift/Subjects/ReplaySubject.swift index d868367b..97332e4c 100644 --- a/RxSwift/Subjects/ReplaySubject.swift +++ b/RxSwift/Subjects/ReplaySubject.swift @@ -99,11 +99,11 @@ class ReplayBufferBase : ReplaySubject { case .Next(let value): addValueToBuffer(value) trim() - _observers.forEach { $0.on(event) } + _observers.on(event) case .Error, .Completed: _stoppedEvent = event trim() - _observers.forEach { $0.on(event) } + _observers.on(event) _observers.removeAll() } diff --git a/RxSwift/Subjects/Variable.swift b/RxSwift/Subjects/Variable.swift index aaeb6bd9..e9c04472 100644 --- a/RxSwift/Subjects/Variable.swift +++ b/RxSwift/Subjects/Variable.swift @@ -32,14 +32,14 @@ public class Variable : ObservableType { */ public var value: E { get { - return _lock.calculateLocked { - return _value - } + _lock.lock(); defer { _lock.unlock() } + return _value } set(newValue) { - _lock.performLocked { - _value = newValue - } + _lock.lock() + _value = newValue + _lock.unlock() + _subject.on(.Next(newValue)) } } diff --git a/RxTests/PerformanceTests/main.swift b/RxTests/PerformanceTests/main.swift index 8d5f179c..9209d000 100644 --- a/RxTests/PerformanceTests/main.swift +++ b/RxTests/PerformanceTests/main.swift @@ -12,82 +12,19 @@ import RxCocoa import AppKit import CoreLocation -let NumberOfIterations = 1000 - -func approxValuePerIteration(total: Int) -> UInt64 { - return UInt64(round(Double(total) / Double(NumberOfIterations))) -} - -func approxValuePerIteration(total: UInt64) -> UInt64 { - return UInt64(round(Double(total) / Double(NumberOfIterations))) -} - -func measureTime(@noescape work: () -> ()) -> UInt64 { - var timebaseInfo: mach_timebase_info = mach_timebase_info() - let res = mach_timebase_info(&timebaseInfo) - - assert(res == 0) - - let start = mach_absolute_time() - for _ in 0 ..< NumberOfIterations { - work() - } - let timeInNano = (mach_absolute_time() - start) * UInt64(timebaseInfo.numer) / UInt64(timebaseInfo.denom) - - return approxValuePerIteration(timeInNano) / UInt64(NumberOfIterations) -} - -func measureMemoryUsage(@noescape work: () -> ()) -> (bytesAllocated: UInt64, allocations: UInt64) { - let (bytes, allocations) = getMemoryInfo() - for _ in 0 ..< NumberOfIterations { - work() - } - let (bytesAfter, allocationsAfter) = getMemoryInfo() - - return (approxValuePerIteration(bytesAfter - bytes), approxValuePerIteration(allocationsAfter - allocations)) -} - let bechmarkTime = true -func compareTwoImplementations(@noescape first first: () -> (), @noescape second: () -> ()) { - // first warm up to keep it fair - first() - second() - - let time1: UInt64 - let time2: UInt64 - - if bechmarkTime { - time1 = measureTime(first) - time2 = measureTime(second) - } - else { - time1 = 0 - time2 = 0 - } - - registerMallocHooks() - - let memory1 = measureMemoryUsage(first) - let memory2 = measureMemoryUsage(second) - - // this is good enough - print(String(format: "#1 implementation %8d bytes %4d allocations %5d useconds", arguments: [ - memory1.bytesAllocated, - memory1.allocations, - time1 - ])) - print(String(format: "#2 implementation %8d bytes %4d allocations %5d useconds", arguments: [ - memory2.bytesAllocated, - memory2.allocations, - time2 - ])) +func allocation() { + } -compareTwoImplementations(first: { +compareTwoImplementations(benchmarkTime: true, first: { let publishSubject = PublishSubject() - publishSubject + let a = just(1) + + //combineLatest(a, + publishSubject .shareReplay(1) //.map { $0 } //.filter { _ in true }// ){ x, _ in x } diff --git a/RxTests/RxSwiftTests/TestImplementations/Mocks/HotObservable.swift b/RxTests/RxSwiftTests/TestImplementations/Mocks/HotObservable.swift index 45ecb62d..bbaea4d2 100644 --- a/RxTests/RxSwiftTests/TestImplementations/Mocks/HotObservable.swift +++ b/RxTests/RxSwiftTests/TestImplementations/Mocks/HotObservable.swift @@ -30,7 +30,7 @@ class HotObservable : ObservableType, ObservableConvertible for recordedEvent in recordedEvents { testScheduler.schedule((), time: recordedEvent.time) { t in - self.observers.forEach { $0.on(recordedEvent.event) } + self.observers.on(recordedEvent.event) return NopDisposable.instance } } diff --git a/RxTests/RxSwiftTests/TestImplementations/Mocks/PrimitiveHotObservable.swift b/RxTests/RxSwiftTests/TestImplementations/Mocks/PrimitiveHotObservable.swift index 14056f6a..a5d47e02 100644 --- a/RxTests/RxSwiftTests/TestImplementations/Mocks/PrimitiveHotObservable.swift +++ b/RxTests/RxSwiftTests/TestImplementations/Mocks/PrimitiveHotObservable.swift @@ -29,7 +29,7 @@ class PrimitiveHotObservable : ObservableType { } func on(event: Event) { - observers.forEach { $0.on(event) } + observers.on(event) } func subscribe(observer: O) -> Disposable { diff --git a/RxTests/RxTests.xcodeproj/project.pbxproj b/RxTests/RxTests.xcodeproj/project.pbxproj index 97e01155..5b5313c8 100644 --- a/RxTests/RxTests.xcodeproj/project.pbxproj +++ b/RxTests/RxTests.xcodeproj/project.pbxproj @@ -1026,6 +1026,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ""; + OTHER_SWIFT_FLAGS = "$(inherits) -D ALLOC_HOOK"; PRODUCT_BUNDLE_IDENTIFIER = "Krunoslav-Zaher.PerformanceTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; @@ -1070,6 +1071,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ""; + OTHER_SWIFT_FLAGS = "$(inherits) -D ALLOC_HOOK"; PRODUCT_BUNDLE_IDENTIFIER = "Krunoslav-Zaher.PerformanceTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; @@ -1113,6 +1115,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ""; + OTHER_SWIFT_FLAGS = "$(inherits) -D ALLOC_HOOK"; PRODUCT_BUNDLE_IDENTIFIER = "Krunoslav-Zaher.PerformanceTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; diff --git a/RxTests/Tests/PerformanceTools.swift b/RxTests/Tests/PerformanceTools.swift index bc2422c9..3ccd1f0c 100644 --- a/RxTests/Tests/PerformanceTools.swift +++ b/RxTests/Tests/PerformanceTools.swift @@ -16,18 +16,27 @@ var bytesAllocated: Int64 = 0 func call0(p: UnsafeMutablePointer<_malloc_zone_t>, size: Int) -> UnsafeMutablePointer { OSAtomicIncrement64(&allocCalls) OSAtomicAdd64(Int64(size), &bytesAllocated) +#if ALLOC_HOOK + allocation() +#endif return mallocFunctions[0](p, size) } func call1(p: UnsafeMutablePointer<_malloc_zone_t>, size: Int) -> UnsafeMutablePointer { OSAtomicIncrement64(&allocCalls) OSAtomicAdd64(Int64(size), &bytesAllocated) +#if ALLOC_HOOK + allocation() +#endif return mallocFunctions[1](p, size) } func call2(p: UnsafeMutablePointer<_malloc_zone_t>, size: Int) -> UnsafeMutablePointer { OSAtomicIncrement64(&allocCalls) OSAtomicAdd64(Int64(size), &bytesAllocated) +#if ALLOC_HOOK + allocation() +#endif return mallocFunctions[2](p, size) } @@ -85,3 +94,108 @@ func registerMallocHooks() { } } +// MARK: Benchmark tools + +let NumberOfIterations = 10000 + +class A { + let _0 = 0 + let _1 = 0 + let _2 = 0 + let _3 = 0 + let _4 = 0 + let _5 = 0 + let _6 = 0 +} + +class B { + var a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29] +} + +let numberOfObjects = 1000000 +let aliveAtTheEnd = numberOfObjects / 10 + +var objects: [AnyObject] = [] + +func fragmentMemory() { + objects = [AnyObject](count: aliveAtTheEnd, repeatedValue: A()) + for _ in 0 ..< numberOfObjects { + objects[Int(arc4random_uniform(UInt32(aliveAtTheEnd)))] = arc4random_uniform(2) == 0 ? A() : B() + } +} + +func approxValuePerIteration(total: Int) -> UInt64 { + return UInt64(round(Double(total) / Double(NumberOfIterations))) +} + +func approxValuePerIteration(total: UInt64) -> UInt64 { + return UInt64(round(Double(total) / Double(NumberOfIterations))) +} + +func measureTime(@noescape work: () -> ()) -> UInt64 { + var timebaseInfo: mach_timebase_info = mach_timebase_info() + let res = mach_timebase_info(&timebaseInfo) + + assert(res == 0) + + let start = mach_absolute_time() + for _ in 0 ..< NumberOfIterations { + work() + } + let timeInNano = (mach_absolute_time() - start) * UInt64(timebaseInfo.numer) / UInt64(timebaseInfo.denom) + + return approxValuePerIteration(timeInNano) / 1000 +} + +func measureMemoryUsage(@noescape work: () -> ()) -> (bytesAllocated: UInt64, allocations: UInt64) { + let (bytes, allocations) = getMemoryInfo() + for _ in 0 ..< NumberOfIterations { + work() + } + let (bytesAfter, allocationsAfter) = getMemoryInfo() + + return (approxValuePerIteration(bytesAfter - bytes), approxValuePerIteration(allocationsAfter - allocations)) +} + +func compareTwoImplementations(benchmarkTime benchmarkTime: Bool, @noescape first: () -> (), @noescape second: () -> ()) { + print("Fragmenting memory ...") + fragmentMemory() + print("Benchmarking ...") + + // first warm up to keep it fair + + let time1: UInt64 + let time2: UInt64 + + if benchmarkTime { + first() + second() + + time1 = measureTime(first) + time2 = measureTime(second) + } + else { + time1 = 0 + time2 = 0 + } + + registerMallocHooks() + + first() + second() + + let memory1 = measureMemoryUsage(first) + let memory2 = measureMemoryUsage(second) + + // this is good enough + print(String(format: "#1 implementation %8d bytes %4d allocations %5d useconds", arguments: [ + memory1.bytesAllocated, + memory1.allocations, + time1 + ])) + print(String(format: "#2 implementation %8d bytes %4d allocations %5d useconds", arguments: [ + memory2.bytesAllocated, + memory2.allocations, + time2 + ])) +} From 6fdb23e222590dc322d0518fbac22d26151a4f55 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 25 Oct 2015 21:46:27 +0100 Subject: [PATCH 05/19] Replaces `Array` with `ContiguousArray` for `Queue` buffer data structure. --- RxSwift/DataStructures/Queue.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RxSwift/DataStructures/Queue.swift b/RxSwift/DataStructures/Queue.swift index 124f32c7..43db307c 100644 --- a/RxSwift/DataStructures/Queue.swift +++ b/RxSwift/DataStructures/Queue.swift @@ -24,7 +24,7 @@ public struct Queue: SequenceType { private let _resizeFactor = 2 - private var _storage: [T?] + private var _storage: ContiguousArray private var _count: Int private var _pushNextIndex: Int private var _initialCapacity: Int @@ -41,10 +41,10 @@ public struct Queue: SequenceType { _pushNextIndex = 0 if capacity > 0 { - _storage = [T?](count: capacity, repeatedValue: nil) + _storage = ContiguousArray(count: capacity, repeatedValue: nil) } else { - _storage = [] + _storage = ContiguousArray() } } @@ -83,7 +83,7 @@ public struct Queue: SequenceType { } mutating private func resizeTo(size: Int) { - var newStorage = [T?](count: size, repeatedValue: nil) + var newStorage = ContiguousArray(count: size, repeatedValue: nil) let count = _count From f86a5923d5880003982051595443d24783c7f90a Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Mon, 26 Oct 2015 12:12:01 +0100 Subject: [PATCH 06/19] Optimizes `Bag`. --- RxSwift/DataStructures/Bag.swift | 160 +++++++++++++- RxSwift/Disposables/CompositeDisposable.swift | 2 +- RxTests/RxSwiftTests/Tests/BagTest.swift | 206 ++++++++++++++---- 3 files changed, 307 insertions(+), 61 deletions(-) diff --git a/RxSwift/DataStructures/Bag.swift b/RxSwift/DataStructures/Bag.swift index 72968fe4..2f023b6c 100644 --- a/RxSwift/DataStructures/Bag.swift +++ b/RxSwift/DataStructures/Bag.swift @@ -7,6 +7,9 @@ // import Foundation +import Swift + +let conciseArrayMaxSize = 30 /** Class that enables using memory allocations as a means to uniquely identify objects. @@ -16,12 +19,31 @@ class Identity { var _forceAllocation: Int32 = 0 } +func hash(_x: Int) -> Int { + var x = _x + x = ((x >> 16) ^ x) &* 0x45d9f3b; + x = ((x >> 16) ^ x) &* 0x45d9f3b; + x = ((x >> 16) ^ x); + return x; +} + /** Unique identifier for object added to `Bag`. */ -public struct BagKey : Equatable { +public struct BagKey : Hashable { let uniqueIdentity: Identity? let key: Int + + public var hashValue: Int { + get { + if let uniqueIdentity = uniqueIdentity { + return hash(key) ^ (unsafeAddressOf(uniqueIdentity).hashValue) + } + else { + return hash(key) + } + } + } } /** @@ -52,8 +74,21 @@ public struct Bag : CustomStringConvertible { private var _uniqueIdentity: Identity? private var _nextKey: ScopeUniqueTokenType = 0 - - var _pairs = ContiguousArray() + + // data + + // first fill inline variables + private var _key0: BagKey? = nil + private var _value0: T? = nil + + private var _key1: BagKey? = nil + private var _value1: T? = nil + + // then fill "array dictionary" + private var _pairs = ContiguousArray() + + // last is sparse dictionary + private var _dictionary: [BagKey : T]? = nil /** Creates new empty `Bag`. @@ -69,7 +104,7 @@ public struct Bag : CustomStringConvertible { return "\(self.count) elements in Bag" } } - + /** Inserts `value` into bag. @@ -86,10 +121,36 @@ public struct Bag : CustomStringConvertible { if _nextKey == 0 { _uniqueIdentity = Identity() } - + let key = BagKey(uniqueIdentity: _uniqueIdentity, key: _nextKey) - - _pairs.append(key: key, value: element) + + if _key0 == nil { + _key0 = key + _value0 = element + return key + } + + if _key1 == nil { + _key1 = key + _value1 = element + return key + } + + if _dictionary != nil { + _dictionary![key] = element + return key + } + + if _pairs.count < conciseArrayMaxSize { + _pairs.append(key: key, value: element) + return key + } + + if _dictionary == nil { + _dictionary = [:] + } + + _dictionary![key] = element return key } @@ -98,14 +159,20 @@ public struct Bag : CustomStringConvertible { - returns: Number of elements in bag. */ public var count: Int { - return _pairs.count + return _pairs.count + (_value0 != nil ? 1 : 0) + (_value1 != nil ? 1 : 0) + (_dictionary?.count ?? 0) } /** Removes all elements from bag and clears capacity. */ public mutating func removeAll() { + _key0 = nil + _value0 = nil + _key1 = nil + _value1 = nil + _pairs.removeAll(keepCapacity: false) + _dictionary?.removeAll(keepCapacity: false) } /** @@ -115,6 +182,24 @@ public struct Bag : CustomStringConvertible { - returns: Element that bag contained, or nil in case element was already removed. */ public mutating func removeKey(key: BagKey) -> T? { + if _key0 == key { + _key0 = nil + let value = _value0! + _value0 = nil + return value + } + + if _key1 == key { + _key1 = nil + let value = _value1! + _value1 = nil + return value + } + + if let existingObject = _dictionary?.removeValueForKey(key) { + return existingObject + } + for i in 0 ..< _pairs.count { if _pairs[i].key == key { let value = _pairs[i].value @@ -122,7 +207,7 @@ public struct Bag : CustomStringConvertible { return value } } - + return nil } } @@ -136,11 +221,28 @@ extension Bag { - parameter action: Enumeration closure. */ public func forEach(@noescape action: (T) -> Void) { - let pairs = self._pairs - + let pairs = _pairs + let value0 = _value0 + let value1 = _value1 + let dictionary = _dictionary + + if let value0 = value0 { + action(value0) + } + + if let value1 = value1 { + action(value1) + } + for i in 0 ..< pairs.count { action(pairs[i].value) } + + if dictionary?.count ?? 0 > 0 { + for element in dictionary!.values { + action(element) + } + } } } @@ -152,20 +254,54 @@ extension Bag where T: ObserverType { */ public func on(event: Event) { let pairs = self._pairs + let value0 = _value0 + let value1 = _value1 + let dictionary = _dictionary + + if let value0 = value0 { + value0.on(event) + } + + if let value1 = value1 { + value1.on(event) + } for i in 0 ..< pairs.count { pairs[i].value.on(event) } + + if dictionary?.count ?? 0 > 0 { + for element in dictionary!.values { + element.on(event) + } + } } } /** Dispatches `dispose` to all disposables contained inside bag. */ -func disposeFromBag(bag: Bag) { +public func disposeAllIn(bag: Bag) { let pairs = bag._pairs + let value0 = bag._value0 + let value1 = bag._value1 + let dictionary = bag._dictionary + + if let value0 = value0 { + value0.dispose() + } + + if let value1 = value1 { + value1.dispose() + } for i in 0 ..< pairs.count { pairs[i].value.dispose() } + + if dictionary?.count ?? 0 > 0 { + for element in dictionary!.values { + element.dispose() + } + } } diff --git a/RxSwift/Disposables/CompositeDisposable.swift b/RxSwift/Disposables/CompositeDisposable.swift index b832f4c2..27212d8b 100644 --- a/RxSwift/Disposables/CompositeDisposable.swift +++ b/RxSwift/Disposables/CompositeDisposable.swift @@ -107,7 +107,7 @@ public class CompositeDisposable : DisposeBase, Disposable, Cancelable { */ public func dispose() { if let disposables = _dispose() { - disposeFromBag(disposables) + disposeAllIn(disposables) } } diff --git a/RxTests/RxSwiftTests/Tests/BagTest.swift b/RxTests/RxSwiftTests/Tests/BagTest.swift index b3f9be65..9a5cb5aa 100644 --- a/RxTests/RxSwiftTests/Tests/BagTest.swift +++ b/RxTests/RxSwiftTests/Tests/BagTest.swift @@ -20,92 +20,202 @@ extension BagTest { typealias DoSomething = () -> Void typealias KeyType = Bag.KeyType - func numberOfActionsAfter(nInsertions: Int, deletionsFromStart: Int) { - var increment = 0 - - var bag = Bag() + func numberOfActionsAfter(nInsertions: Int, deletionsFromStart: Int, createNew: () -> T, bagAction: (RxMutableBox>) -> ()) { + let bag = RxMutableBox(Bag()) var keys = [KeyType]() for _ in 0 ..< nInsertions { - keys.append(bag.insert({ - increment++ - })) + keys.append(bag.value.insert(createNew())) } for i in 0 ..< deletionsFromStart { let key = keys[i] - bag.removeKey(key) + XCTAssertTrue(bag.value.removeKey(key) != nil) } - - bag.forEach { $0() } - - XCTAssertTrue(increment == nInsertions - deletionsFromStart) + + bagAction(bag) } func testBag_deletionsFromStart() { for i in 0 ..< 50 { for j in 0 ... i { - numberOfActionsAfter(i, deletionsFromStart: j) + var numberForEachActions = 0 + var numberObservers = 0 + var numberDisposables = 0 + + numberOfActionsAfter(i, + deletionsFromStart: j, + createNew: { () -> DoSomething in { () -> () in numberForEachActions++ } }, + bagAction: { (bag: RxMutableBox>) in bag.value.forEach { $0() }; XCTAssertTrue(bag.value.count == i - j) } + ) + numberOfActionsAfter(i, + deletionsFromStart: j, + createNew: { () -> AnyObserver in AnyObserver { _ in numberObservers++ } }, + bagAction: { (bag: RxMutableBox>>) in bag.value.on(.Next(1)); XCTAssertTrue(bag.value.count == i - j) } + ) + numberOfActionsAfter(i, + deletionsFromStart: j, + createNew: { () -> Disposable in AnonymousDisposable { numberDisposables++ } }, + bagAction: { (bag: RxMutableBox>) in disposeAllIn(bag.value); XCTAssertTrue(bag.value.count == i - j) } + ) + + XCTAssertTrue(numberForEachActions == i - j) + XCTAssertTrue(numberObservers == i - j) + XCTAssertTrue(numberDisposables == i - j) } } } - func numberOfActionsAfter(nInsertions: Int, deletionsFromEnd: Int) { - var increment = 0 - - var bag = Bag() + func numberOfActionsAfter(nInsertions: Int, deletionsFromEnd: Int, createNew: () -> T, bagAction: (RxMutableBox>) -> ()) { + let bag = RxMutableBox(Bag()) var keys = [KeyType]() for _ in 0 ..< nInsertions { - keys.append(bag.insert({ - increment++ - })) + keys.append(bag.value.insert(createNew())) } for i in 0 ..< deletionsFromEnd { let key = keys[keys.count - 1 - i] - bag.removeKey(key) + XCTAssertTrue(bag.value.removeKey(key) != nil) } - - bag.forEach { $0() } - - XCTAssertTrue(increment == nInsertions - deletionsFromEnd) + + bagAction(bag) } func testBag_deletionsFromEnd() { for i in 0 ..< 50 { for j in 0 ... i { - numberOfActionsAfter(i, deletionsFromEnd: j) + var numberForEachActions = 0 + var numberObservers = 0 + var numberDisposables = 0 + + numberOfActionsAfter(i, + deletionsFromStart: j, + createNew: { () -> DoSomething in { () -> () in numberForEachActions++ } }, + bagAction: { (bag: RxMutableBox>) in bag.value.forEach { $0() }; XCTAssertTrue(bag.value.count == i - j) } + ) + numberOfActionsAfter(i, + deletionsFromStart: j, + createNew: { () -> AnyObserver in AnyObserver { _ in numberObservers++ } }, + bagAction: { (bag: RxMutableBox>>) in bag.value.on(.Next(1)); XCTAssertTrue(bag.value.count == i - j) } + ) + numberOfActionsAfter(i, + deletionsFromStart: j, + createNew: { () -> Disposable in AnonymousDisposable { numberDisposables++ } }, + bagAction: { (bag: RxMutableBox>) in disposeAllIn(bag.value); XCTAssertTrue(bag.value.count == i - j) } + ) + + XCTAssertTrue(numberForEachActions == i - j) + XCTAssertTrue(numberObservers == i - j) + XCTAssertTrue(numberDisposables == i - j) } } } func testBag_immutableForeach() { - var increment = 0 - - var bag = Bag() - - var keys = [KeyType]() - - for _ in 0 ..< 10 { - keys.append(bag.insert({ - increment++ - })) - } - - for _ in 0 ..< 2 { - var j = 0 - bag.forEach { c in - j++ - if j == 5 { - bag.removeAll() - } - c() + for breakAt in 0 ..< 50 { + var increment1 = 0 + var increment2 = 0 + var increment3 = 0 + + let bag1 = RxMutableBox(Bag()) + let bag2 = RxMutableBox(Bag>()) + let bag3 = RxMutableBox(Bag()) + + for _ in 0 ..< 50 { + bag1.value.insert({ + if increment1 == breakAt { + bag1.value.removeAll() + } + increment1++ + }) + bag2.value.insert(AnyObserver { _ in + if increment2 == breakAt { + bag2.value.removeAll() + } + increment2++ + }) + bag3.value.insert(AnonymousDisposable { _ in + if increment3 == breakAt { + bag3.value.removeAll() + } + increment3++ + }) } + + for _ in 0 ..< 2 { + bag1.value.forEach { c in + c() + } + + bag2.value.on(.Next(1)) + + disposeAllIn(bag3.value) + } + + XCTAssertEqual(increment1, 50) + } + } + + func testBag_removeAll() { + var numberForEachActions = 0 + var numberObservers = 0 + var numberDisposables = 0 + + numberOfActionsAfter(100, + deletionsFromStart: 0, + createNew: { () -> DoSomething in { () -> () in numberForEachActions++ } }, + bagAction: { (bag: RxMutableBox>) in bag.value.removeAll(); bag.value.forEach { $0() } } + ) + numberOfActionsAfter(100, + deletionsFromStart: 0, + createNew: { () -> AnyObserver in AnyObserver { _ in numberObservers++ } }, + bagAction: { (bag: RxMutableBox>>) in bag.value.removeAll(); bag.value.on(.Next(1)); } + ) + numberOfActionsAfter(100, + deletionsFromStart: 0, + createNew: { () -> Disposable in AnonymousDisposable { numberDisposables++ } }, + bagAction: { (bag: RxMutableBox>) in bag.value.removeAll(); disposeAllIn(bag.value); } + ) + + XCTAssertTrue(numberForEachActions == 0) + XCTAssertTrue(numberObservers == 0) + XCTAssertTrue(numberDisposables == 0) + } + + func testBag_complexityTestFromFront() { + var bag = Bag() + + let limit = 100000 + + var increment = 0 + + var keys: [Bag.KeyType] = [] + for _ in 0..() + + let limit = 100000 + + var increment = 0 + + var keys: [Bag.KeyType] = [] + for _ in 0.. Date: Mon, 26 Oct 2015 12:19:36 +0100 Subject: [PATCH 07/19] Improves naming in `Bag.swift`. --- RxSwift/DataStructures/Bag.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RxSwift/DataStructures/Bag.swift b/RxSwift/DataStructures/Bag.swift index 2f023b6c..3bc66e69 100644 --- a/RxSwift/DataStructures/Bag.swift +++ b/RxSwift/DataStructures/Bag.swift @@ -9,7 +9,7 @@ import Foundation import Swift -let conciseArrayMaxSize = 30 +let arrayDictionaryMaxSize = 30 /** Class that enables using memory allocations as a means to uniquely identify objects. @@ -141,7 +141,7 @@ public struct Bag : CustomStringConvertible { return key } - if _pairs.count < conciseArrayMaxSize { + if _pairs.count < arrayDictionaryMaxSize { _pairs.append(key: key, value: element) return key } From aada6618891535ee4e95eb2f0b0620f55fd315a8 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sat, 31 Oct 2015 10:35:08 +0100 Subject: [PATCH 08/19] Low hanging fruit optimizations for `just`, `failWith`, `never`, `empty`, `flatMap`. --- .../Observables/Implementations/Empty.swift | 2 +- .../Implementations/FailWith.swift | 2 +- .../Observables/Implementations/FlatMap.swift | 43 ++++++++----------- .../Observables/Implementations/Just.swift | 2 +- .../Observables/Implementations/Never.swift | 2 +- RxTests/PerformanceTests/main.swift | 5 ++- 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/RxSwift/Observables/Implementations/Empty.swift b/RxSwift/Observables/Implementations/Empty.swift index 6b9fcde7..d2ebb188 100644 --- a/RxSwift/Observables/Implementations/Empty.swift +++ b/RxSwift/Observables/Implementations/Empty.swift @@ -9,7 +9,7 @@ import Foundation class Empty : Producer { - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func subscribe(observer: O) -> Disposable { observer.on(.Completed) return NopDisposable.instance } diff --git a/RxSwift/Observables/Implementations/FailWith.swift b/RxSwift/Observables/Implementations/FailWith.swift index 8350175b..3b771c5b 100644 --- a/RxSwift/Observables/Implementations/FailWith.swift +++ b/RxSwift/Observables/Implementations/FailWith.swift @@ -15,7 +15,7 @@ class FailWith : Producer { _error = error } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func subscribe(observer: O) -> Disposable { observer.on(.Error(_error)) return NopDisposable.instance } diff --git a/RxSwift/Observables/Implementations/FlatMap.swift b/RxSwift/Observables/Implementations/FlatMap.swift index c623ad44..11ebef1f 100644 --- a/RxSwift/Observables/Implementations/FlatMap.swift +++ b/RxSwift/Observables/Implementations/FlatMap.swift @@ -27,14 +27,14 @@ class FlatMapSinkIter) { switch event { case .Next(let value): - _parent._lock.performLocked { + _parent._lock.lock(); defer { _parent._lock.unlock() } // lock { _parent.observer?.on(.Next(value)) - } + // } case .Error(let error): - _parent._lock.performLocked { + _parent._lock.lock(); defer { _parent._lock.unlock() } // lock { _parent.observer?.on(.Error(error)) _parent.dispose() - } + // } case .Completed: _parent._group.removeDisposable(_disposeKey) // If this has returned true that means that `Completed` should be sent. @@ -43,10 +43,10 @@ class FlatMapSinkIter: Producer { setSink(sink) return sink.run() } - } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Just.swift b/RxSwift/Observables/Implementations/Just.swift index 1218bbb1..fecb935a 100644 --- a/RxSwift/Observables/Implementations/Just.swift +++ b/RxSwift/Observables/Implementations/Just.swift @@ -15,7 +15,7 @@ class Just : Producer { _element = element } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func subscribe(observer: O) -> Disposable { observer.on(.Next(_element)) observer.on(.Completed) return NopDisposable.instance diff --git a/RxSwift/Observables/Implementations/Never.swift b/RxSwift/Observables/Implementations/Never.swift index 3ea38ca0..1b20b277 100644 --- a/RxSwift/Observables/Implementations/Never.swift +++ b/RxSwift/Observables/Implementations/Never.swift @@ -9,7 +9,7 @@ import Foundation class Never : Producer { - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func subscribe(observer: O) -> Disposable { return NopDisposable.instance } } \ No newline at end of file diff --git a/RxTests/PerformanceTests/main.swift b/RxTests/PerformanceTests/main.swift index 9209d000..289abde2 100644 --- a/RxTests/PerformanceTests/main.swift +++ b/RxTests/PerformanceTests/main.swift @@ -21,14 +21,15 @@ func allocation() { compareTwoImplementations(benchmarkTime: true, first: { let publishSubject = PublishSubject() - let a = just(1) + //let a = just(1) //combineLatest(a, publishSubject - .shareReplay(1) + //.shareReplay(1) //.map { $0 } //.filter { _ in true }// ){ x, _ in x } //.map { $0 } + .flatMap { just($0) } .subscribeNext { _ in } From 28c97d94130a62a197cb905c2e5b867ec43a48cd Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sat, 31 Oct 2015 19:32:20 +0100 Subject: [PATCH 09/19] Enables testability. --- Rx.xcodeproj/project.pbxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index e7949ad6..99c1d709 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -3096,6 +3096,7 @@ ENABLE_BITCODE = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = "TRACE_RESOURCES=1"; From 22de82ba2bbc7c16387affa3998a083e5906933a Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sat, 31 Oct 2015 19:32:36 +0100 Subject: [PATCH 10/19] Removes disposable from `Sink`. --- RxSwift/Observables/Implementations/Sink.swift | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/RxSwift/Observables/Implementations/Sink.swift b/RxSwift/Observables/Implementations/Sink.swift index 7aeaee53..62851338 100644 --- a/RxSwift/Observables/Implementations/Sink.swift +++ b/RxSwift/Observables/Implementations/Sink.swift @@ -10,7 +10,7 @@ import Foundation class Sink : Disposable { private var _lock = SpinLock() - + // state private var _observer: O? private var _cancel: Disposable @@ -23,13 +23,6 @@ class Sink : Disposable { } } - var cancel: Disposable { - get { - _lock.lock(); defer { _lock.unlock() } - return _cancel - } - } - init(observer: O, cancel: Disposable) { #if TRACE_RESOURCES OSAtomicIncrement32(&resourceCount) @@ -38,7 +31,7 @@ class Sink : Disposable { _cancel = cancel } - func _disposeInternal() -> Disposable? { + private func _disposeInternal() -> Disposable? { _lock.lock(); defer { _lock.unlock() } if _disposed { From 13a87af009b1ef7841feb5bc3fb634cd94c0347b Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 1 Nov 2015 11:48:10 +0100 Subject: [PATCH 11/19] Moves disposables combo in `Producer.subscribe` to `Sink`. `SynchronizedOnType` overhauls. --- RxSwift/Disposables/AnonymousDisposable.swift | 2 + .../SingleAssignmentDisposable.swift | 3 + RxSwift/Observables/Implementations/Amb.swift | 12 +- .../Implementations/AnonymousObservable.swift | 12 +- .../Observables/Implementations/Buffer.swift | 56 +++-- .../Observables/Implementations/Catch.swift | 24 +- .../CombineLatest+CollectionType.swift | 95 ++++---- .../Implementations/CombineLatest+arity.swift | 154 ++++++------- .../Implementations/CombineLatest+arity.tt | 14 +- .../Implementations/CombineLatest.swift | 10 +- .../Observables/Implementations/Concat.swift | 14 +- .../Observables/Implementations/Debug.swift | 12 +- .../Implementations/Deferred.swift | 12 +- .../Implementations/DelaySubscription.swift | 17 +- .../DistinctUntilChanged.swift | 12 +- RxSwift/Observables/Implementations/Do.swift | 14 +- .../Implementations/ElementAt.swift | 12 +- .../Observables/Implementations/Filter.swift | 12 +- .../Observables/Implementations/FlatMap.swift | 28 +-- .../Implementations/Generate.swift | 12 +- RxSwift/Observables/Implementations/Map.swift | 26 +-- .../Observables/Implementations/Merge.swift | 213 ++++++++++-------- .../Implementations/Multicast.swift | 12 +- .../Implementations/ObserveOn.swift | 98 ++++---- .../ObserveOnSerialDispatchQueue.swift | 25 +- .../Implementations/Producer.swift | 21 +- .../Observables/Implementations/Range.swift | 12 +- .../Observables/Implementations/Reduce.swift | 12 +- .../Implementations/RefCount.swift | 26 ++- .../Observables/Implementations/Repeat.swift | 13 +- .../Observables/Implementations/Sample.swift | 105 +++++---- .../Observables/Implementations/Scan.swift | 12 +- .../Observables/Implementations/Sink.swift | 28 +-- .../Observables/Implementations/Skip.swift | 25 +- .../Implementations/SkipUntil.swift | 102 +++++---- .../Implementations/SkipWhile.swift | 22 +- .../Implementations/StartWith.swift | 2 +- .../Implementations/SubscribeOn.swift | 12 +- .../Observables/Implementations/Switch.swift | 118 +++++----- .../Observables/Implementations/Take.swift | 64 +++--- .../Implementations/TakeLast.swift | 12 +- .../Implementations/TakeUntil.swift | 82 +++---- .../Implementations/TakeWhile.swift | 30 +-- .../Implementations/Throttle.swift | 105 ++++----- .../Observables/Implementations/Timer.swift | 22 +- .../Observables/Implementations/ToArray.swift | 14 +- .../Observables/Implementations/Using.swift | 12 +- .../Implementations/WithLatestFrom.swift | 92 ++++---- .../Implementations/Zip+CollectionType.swift | 19 +- .../Implementations/Zip+arity.swift | 154 ++++++------- .../Observables/Implementations/Zip+arity.tt | 14 +- RxSwift/Observables/Implementations/Zip.swift | 48 ++-- RxSwift/Observers/TailRecursiveSink.swift | 4 +- .../Schedulers/CurrentThreadScheduler.swift | 6 +- RxTests/PerformanceTests/main.swift | 10 +- ...rvable+StandardSequenceOperatorsTest.swift | 6 +- RxTests/RxTest.swift | 2 +- .../xcschemes/RxTests-OSX.xcscheme | 2 +- .../xcschemes/RxTests-iOS.xcscheme | 2 +- .../xcschemes/RxTests-tvOS.xcscheme | 2 +- 60 files changed, 1090 insertions(+), 1023 deletions(-) diff --git a/RxSwift/Disposables/AnonymousDisposable.swift b/RxSwift/Disposables/AnonymousDisposable.swift index dffdd30d..b9aef47a 100644 --- a/RxSwift/Disposables/AnonymousDisposable.swift +++ b/RxSwift/Disposables/AnonymousDisposable.swift @@ -45,6 +45,8 @@ public final class AnonymousDisposable : DisposeBase, Cancelable { */ public func dispose() { if OSAtomicCompareAndSwap32(0, 1, &_disposed) { + assert(_disposed == 1) + if let action = _disposeAction { _disposeAction = nil action() diff --git a/RxSwift/Disposables/SingleAssignmentDisposable.swift b/RxSwift/Disposables/SingleAssignmentDisposable.swift index 8b2858bd..f74e22eb 100644 --- a/RxSwift/Disposables/SingleAssignmentDisposable.swift +++ b/RxSwift/Disposables/SingleAssignmentDisposable.swift @@ -72,6 +72,9 @@ public class SingleAssignmentDisposable : DisposeBase, Disposable, Cancelable { Disposes the underlying disposable. */ public func dispose() { + if _disposed { + return + } _dispose()?.dispose() } diff --git a/RxSwift/Observables/Implementations/Amb.swift b/RxSwift/Observables/Implementations/Amb.swift index 9c19d568..439cbd65 100644 --- a/RxSwift/Observables/Implementations/Amb.swift +++ b/RxSwift/Observables/Implementations/Amb.swift @@ -58,9 +58,9 @@ class AmbSink : Sink { // state private var _choice = AmbState.Neither - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -114,9 +114,9 @@ class Amb: Producer { _right = right } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = AmbSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = AmbSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/AnonymousObservable.swift b/RxSwift/Observables/Implementations/AnonymousObservable.swift index 74379c2d..506f8b31 100644 --- a/RxSwift/Observables/Implementations/AnonymousObservable.swift +++ b/RxSwift/Observables/Implementations/AnonymousObservable.swift @@ -16,8 +16,8 @@ class AnonymousObservableSink : Sink, ObserverType { // state private var _isStopped: Int32 = 0 - override init(observer: O, cancel: Disposable) { - super.init(observer: observer, cancel: cancel) + override init(observer: O) { + super.init(observer: observer) } func on(event: Event) { @@ -49,9 +49,9 @@ public class AnonymousObservable : Producer { _subscribeHandler = subscribeHandler } - public override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = AnonymousObservableSink(observer: observer, cancel: cancel) - setSink(sink) - return sink.run(self) + public override func run(observer: O) -> Disposable { + let sink = AnonymousObservableSink(observer: observer) + sink.disposable = sink.run(self) + return sink } } diff --git a/RxSwift/Observables/Implementations/Buffer.swift b/RxSwift/Observables/Implementations/Buffer.swift index eb380461..1c932ed3 100644 --- a/RxSwift/Observables/Implementations/Buffer.swift +++ b/RxSwift/Observables/Implementations/Buffer.swift @@ -22,29 +22,33 @@ class BufferTimeCount : Producer<[Element]> { _scheduler = scheduler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = BufferTimeCountSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = BufferTimeCountSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } -class BufferTimeCountSink : Sink, ObserverType { +class BufferTimeCountSink + : Sink + , LockOwnerType + , ObserverType + , SynchronizedOnType { typealias Parent = BufferTimeCount typealias E = Element private let _parent: Parent - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private let _timerD = SerialDisposable() private var _buffer = [Element]() private var _windowID = 0 - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -64,24 +68,26 @@ class BufferTimeCountSink) { - _lock.performLocked { - switch event { - case .Next(let element): - _buffer.append(element) - - if _buffer.count == _parent._count { - startNewWindowAndSendCurrentOne() - } - - case .Error(let error): - _buffer = [] - observer?.on(.Error(error)) - dispose() - case .Completed: - observer?.on(.Next(_buffer)) - observer?.on(.Completed) - dispose() + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next(let element): + _buffer.append(element) + + if _buffer.count == _parent._count { + startNewWindowAndSendCurrentOne() } + + case .Error(let error): + _buffer = [] + observer?.on(.Error(error)) + dispose() + case .Completed: + observer?.on(.Next(_buffer)) + observer?.on(.Completed) + dispose() } } diff --git a/RxSwift/Observables/Implementations/Catch.swift b/RxSwift/Observables/Implementations/Catch.swift index 3924948c..eaccfc8e 100644 --- a/RxSwift/Observables/Implementations/Catch.swift +++ b/RxSwift/Observables/Implementations/Catch.swift @@ -39,9 +39,9 @@ class CatchSink : Sink, ObserverType { private let _parent: Parent private let _subscription = SerialDisposable() - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -86,10 +86,10 @@ class Catch : Producer { _handler = handler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CatchSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CatchSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -101,8 +101,8 @@ class CatchSequenceSink) { @@ -148,9 +148,9 @@ class CatchSequence(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CatchSequenceSink(observer: observer, cancel: cancel) - setSink(sink) - return sink.run(self.sources.generate()) + override func run(observer: O) -> Disposable { + let sink = CatchSequenceSink(observer: observer) + sink.disposable = sink.run(self.sources.generate()) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift b/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift index e61c4390..e1e2bb82 100644 --- a/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift +++ b/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift @@ -8,48 +8,49 @@ import Foundation -class CombineLatestCollectionTypeSink : Sink { +class CombineLatestCollectionTypeSink + : Sink { typealias Parent = CombineLatestCollectionType typealias SourceElement = C.Generator.Element.E - let parent: Parent - - let lock = NSRecursiveLock() + let _parent: Parent + let _lock = NSRecursiveLock() + // state - var numberOfValues = 0 - var values: [SourceElement?] - var isDone: [Bool] - var numberOfDone = 0 - var subscriptions: [SingleAssignmentDisposable] + var _numberOfValues = 0 + var _values: [SourceElement?] + var _isDone: [Bool] + var _numberOfDone = 0 + var _subscriptions: [SingleAssignmentDisposable] - init(parent: Parent, observer: O, cancel: Disposable) { - self.parent = parent - self.values = [SourceElement?](count: parent.count, repeatedValue: nil) - self.isDone = [Bool](count: parent.count, repeatedValue: false) - self.subscriptions = Array() - self.subscriptions.reserveCapacity(parent.count) + init(parent: Parent, observer: O) { + _parent = parent + _values = [SourceElement?](count: parent._count, repeatedValue: nil) + _isDone = [Bool](count: parent._count, repeatedValue: false) + _subscriptions = Array() + _subscriptions.reserveCapacity(parent._count) - for _ in 0 ..< parent.count { - self.subscriptions.append(SingleAssignmentDisposable()) + for _ in 0 ..< parent._count { + _subscriptions.append(SingleAssignmentDisposable()) } - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event, atIndex: Int) { - lock.performLocked { + _lock.lock(); defer { _lock.unlock() } // { switch event { case .Next(let element): - if values[atIndex] == nil { - numberOfValues++ + if _values[atIndex] == nil { + _numberOfValues++ } - values[atIndex] = element + _values[atIndex] = element - if numberOfValues < parent.count { - let numberOfOthersThatAreDone = self.numberOfDone - (isDone[atIndex] ? 1 : 0) - if numberOfOthersThatAreDone == self.parent.count - 1 { + if _numberOfValues < _parent._count { + let numberOfOthersThatAreDone = self._numberOfDone - (_isDone[atIndex] ? 1 : 0) + if numberOfOthersThatAreDone == self._parent._count - 1 { observer?.on(.Completed) dispose() } @@ -57,7 +58,7 @@ class CombineLatestCollectionTypeSink Disposable { var j = 0 - for i in parent.sources.startIndex ..< parent.sources.endIndex { + for i in _parent._sources.startIndex ..< _parent._sources.endIndex { let index = j - let source = self.parent.sources[i].asObservable() - self.subscriptions[j].disposable = source.subscribe(AnyObserver { event in + let source = _parent._sources[i].asObservable() + _subscriptions[j].disposable = source.subscribe(AnyObserver { event in self.on(event, atIndex: index) }) j++ } - return CompositeDisposable(disposables: self.subscriptions.map { $0 }) + return CompositeDisposable(disposables: _subscriptions.map { $0 }) } } class CombineLatestCollectionType : Producer { typealias ResultSelector = [C.Generator.Element.E] throws -> R - let sources: C - let resultSelector: ResultSelector - let count: Int - + let _sources: C + let _resultSelector: ResultSelector + let _count: Int + init(sources: C, resultSelector: ResultSelector) { - self.sources = sources - self.resultSelector = resultSelector - self.count = Int(self.sources.count.toIntMax()) + _sources = sources + _resultSelector = resultSelector + _count = Int(self._sources.count.toIntMax()) } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestCollectionTypeSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestCollectionTypeSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/CombineLatest+arity.swift b/RxSwift/Observables/Implementations/CombineLatest+arity.swift index da65b503..320e701e 100644 --- a/RxSwift/Observables/Implementations/CombineLatest+arity.swift +++ b/RxSwift/Observables/Implementations/CombineLatest+arity.swift @@ -39,17 +39,17 @@ class CombineLatestSink2_ : CombineLatestSink { var _latestElement1: E1! = nil var _latestElement2: E2! = nil - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 2, observer: observer, cancel: cancel) + super.init(arity: 2, observer: observer) } func run() -> Disposable { let subscription1 = SingleAssignmentDisposable() let subscription2 = SingleAssignmentDisposable() - let observer1 = CombineLatestObserver(lock: lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) - let observer2 = CombineLatestObserver(lock: lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) + let observer1 = CombineLatestObserver(lock: _lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) + let observer2 = CombineLatestObserver(lock: _lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) subscription1.disposable = _parent._source1.subscribe(observer1) subscription2.disposable = _parent._source2.subscribe(observer2) @@ -80,10 +80,10 @@ class CombineLatest2 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink2_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink2_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -117,9 +117,9 @@ class CombineLatestSink3_ : CombineLatestSink { var _latestElement2: E2! = nil var _latestElement3: E3! = nil - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 3, observer: observer, cancel: cancel) + super.init(arity: 3, observer: observer) } func run() -> Disposable { @@ -127,9 +127,9 @@ class CombineLatestSink3_ : CombineLatestSink { let subscription2 = SingleAssignmentDisposable() let subscription3 = SingleAssignmentDisposable() - let observer1 = CombineLatestObserver(lock: lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) - let observer2 = CombineLatestObserver(lock: lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) - let observer3 = CombineLatestObserver(lock: lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) + let observer1 = CombineLatestObserver(lock: _lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) + let observer2 = CombineLatestObserver(lock: _lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) + let observer3 = CombineLatestObserver(lock: _lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) subscription1.disposable = _parent._source1.subscribe(observer1) subscription2.disposable = _parent._source2.subscribe(observer2) @@ -164,10 +164,10 @@ class CombineLatest3 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink3_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink3_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -202,9 +202,9 @@ class CombineLatestSink4_ : CombineLatestSink Disposable { @@ -213,10 +213,10 @@ class CombineLatestSink4_ : CombineLatestSink Void in self._latestElement1 = e }, this: subscription1) - let observer2 = CombineLatestObserver(lock: lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) - let observer3 = CombineLatestObserver(lock: lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) - let observer4 = CombineLatestObserver(lock: lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) + let observer1 = CombineLatestObserver(lock: _lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) + let observer2 = CombineLatestObserver(lock: _lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) + let observer3 = CombineLatestObserver(lock: _lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) + let observer4 = CombineLatestObserver(lock: _lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) subscription1.disposable = _parent._source1.subscribe(observer1) subscription2.disposable = _parent._source2.subscribe(observer2) @@ -255,10 +255,10 @@ class CombineLatest4 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink4_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink4_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -294,9 +294,9 @@ class CombineLatestSink5_ : CombineLatestSi var _latestElement4: E4! = nil var _latestElement5: E5! = nil - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 5, observer: observer, cancel: cancel) + super.init(arity: 5, observer: observer) } func run() -> Disposable { @@ -306,11 +306,11 @@ class CombineLatestSink5_ : CombineLatestSi let subscription4 = SingleAssignmentDisposable() let subscription5 = SingleAssignmentDisposable() - let observer1 = CombineLatestObserver(lock: lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) - let observer2 = CombineLatestObserver(lock: lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) - let observer3 = CombineLatestObserver(lock: lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) - let observer4 = CombineLatestObserver(lock: lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) - let observer5 = CombineLatestObserver(lock: lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) + let observer1 = CombineLatestObserver(lock: _lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) + let observer2 = CombineLatestObserver(lock: _lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) + let observer3 = CombineLatestObserver(lock: _lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) + let observer4 = CombineLatestObserver(lock: _lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) + let observer5 = CombineLatestObserver(lock: _lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) subscription1.disposable = _parent._source1.subscribe(observer1) subscription2.disposable = _parent._source2.subscribe(observer2) @@ -353,10 +353,10 @@ class CombineLatest5 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink5_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink5_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -393,9 +393,9 @@ class CombineLatestSink6_ : CombineLate var _latestElement5: E5! = nil var _latestElement6: E6! = nil - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 6, observer: observer, cancel: cancel) + super.init(arity: 6, observer: observer) } func run() -> Disposable { @@ -406,12 +406,12 @@ class CombineLatestSink6_ : CombineLate let subscription5 = SingleAssignmentDisposable() let subscription6 = SingleAssignmentDisposable() - let observer1 = CombineLatestObserver(lock: lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) - let observer2 = CombineLatestObserver(lock: lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) - let observer3 = CombineLatestObserver(lock: lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) - let observer4 = CombineLatestObserver(lock: lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) - let observer5 = CombineLatestObserver(lock: lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) - let observer6 = CombineLatestObserver(lock: lock, parent: self, index: 5, setLatestValue: { (e: E6) -> Void in self._latestElement6 = e }, this: subscription6) + let observer1 = CombineLatestObserver(lock: _lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) + let observer2 = CombineLatestObserver(lock: _lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) + let observer3 = CombineLatestObserver(lock: _lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) + let observer4 = CombineLatestObserver(lock: _lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) + let observer5 = CombineLatestObserver(lock: _lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) + let observer6 = CombineLatestObserver(lock: _lock, parent: self, index: 5, setLatestValue: { (e: E6) -> Void in self._latestElement6 = e }, this: subscription6) subscription1.disposable = _parent._source1.subscribe(observer1) subscription2.disposable = _parent._source2.subscribe(observer2) @@ -458,10 +458,10 @@ class CombineLatest6 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink6_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink6_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -499,9 +499,9 @@ class CombineLatestSink7_ : Combine var _latestElement6: E6! = nil var _latestElement7: E7! = nil - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 7, observer: observer, cancel: cancel) + super.init(arity: 7, observer: observer) } func run() -> Disposable { @@ -513,13 +513,13 @@ class CombineLatestSink7_ : Combine let subscription6 = SingleAssignmentDisposable() let subscription7 = SingleAssignmentDisposable() - let observer1 = CombineLatestObserver(lock: lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) - let observer2 = CombineLatestObserver(lock: lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) - let observer3 = CombineLatestObserver(lock: lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) - let observer4 = CombineLatestObserver(lock: lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) - let observer5 = CombineLatestObserver(lock: lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) - let observer6 = CombineLatestObserver(lock: lock, parent: self, index: 5, setLatestValue: { (e: E6) -> Void in self._latestElement6 = e }, this: subscription6) - let observer7 = CombineLatestObserver(lock: lock, parent: self, index: 6, setLatestValue: { (e: E7) -> Void in self._latestElement7 = e }, this: subscription7) + let observer1 = CombineLatestObserver(lock: _lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) + let observer2 = CombineLatestObserver(lock: _lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) + let observer3 = CombineLatestObserver(lock: _lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) + let observer4 = CombineLatestObserver(lock: _lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) + let observer5 = CombineLatestObserver(lock: _lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) + let observer6 = CombineLatestObserver(lock: _lock, parent: self, index: 5, setLatestValue: { (e: E6) -> Void in self._latestElement6 = e }, this: subscription6) + let observer7 = CombineLatestObserver(lock: _lock, parent: self, index: 6, setLatestValue: { (e: E7) -> Void in self._latestElement7 = e }, this: subscription7) subscription1.disposable = _parent._source1.subscribe(observer1) subscription2.disposable = _parent._source2.subscribe(observer2) @@ -570,10 +570,10 @@ class CombineLatest7 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink7_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink7_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -612,9 +612,9 @@ class CombineLatestSink8_ : Com var _latestElement7: E7! = nil var _latestElement8: E8! = nil - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 8, observer: observer, cancel: cancel) + super.init(arity: 8, observer: observer) } func run() -> Disposable { @@ -627,14 +627,14 @@ class CombineLatestSink8_ : Com let subscription7 = SingleAssignmentDisposable() let subscription8 = SingleAssignmentDisposable() - let observer1 = CombineLatestObserver(lock: lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) - let observer2 = CombineLatestObserver(lock: lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) - let observer3 = CombineLatestObserver(lock: lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) - let observer4 = CombineLatestObserver(lock: lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) - let observer5 = CombineLatestObserver(lock: lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) - let observer6 = CombineLatestObserver(lock: lock, parent: self, index: 5, setLatestValue: { (e: E6) -> Void in self._latestElement6 = e }, this: subscription6) - let observer7 = CombineLatestObserver(lock: lock, parent: self, index: 6, setLatestValue: { (e: E7) -> Void in self._latestElement7 = e }, this: subscription7) - let observer8 = CombineLatestObserver(lock: lock, parent: self, index: 7, setLatestValue: { (e: E8) -> Void in self._latestElement8 = e }, this: subscription8) + let observer1 = CombineLatestObserver(lock: _lock, parent: self, index: 0, setLatestValue: { (e: E1) -> Void in self._latestElement1 = e }, this: subscription1) + let observer2 = CombineLatestObserver(lock: _lock, parent: self, index: 1, setLatestValue: { (e: E2) -> Void in self._latestElement2 = e }, this: subscription2) + let observer3 = CombineLatestObserver(lock: _lock, parent: self, index: 2, setLatestValue: { (e: E3) -> Void in self._latestElement3 = e }, this: subscription3) + let observer4 = CombineLatestObserver(lock: _lock, parent: self, index: 3, setLatestValue: { (e: E4) -> Void in self._latestElement4 = e }, this: subscription4) + let observer5 = CombineLatestObserver(lock: _lock, parent: self, index: 4, setLatestValue: { (e: E5) -> Void in self._latestElement5 = e }, this: subscription5) + let observer6 = CombineLatestObserver(lock: _lock, parent: self, index: 5, setLatestValue: { (e: E6) -> Void in self._latestElement6 = e }, this: subscription6) + let observer7 = CombineLatestObserver(lock: _lock, parent: self, index: 6, setLatestValue: { (e: E7) -> Void in self._latestElement7 = e }, this: subscription7) + let observer8 = CombineLatestObserver(lock: _lock, parent: self, index: 7, setLatestValue: { (e: E8) -> Void in self._latestElement8 = e }, this: subscription8) subscription1.disposable = _parent._source1.subscribe(observer1) subscription2.disposable = _parent._source2.subscribe(observer2) @@ -689,10 +689,10 @@ class CombineLatest8 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink8_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink8_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } diff --git a/RxSwift/Observables/Implementations/CombineLatest+arity.tt b/RxSwift/Observables/Implementations/CombineLatest+arity.tt index 927f7e0d..89217773 100644 --- a/RxSwift/Observables/Implementations/CombineLatest+arity.tt +++ b/RxSwift/Observables/Implementations/CombineLatest+arity.tt @@ -38,9 +38,9 @@ class CombineLatestSink<%= i %>_<<%= (Array(1...i).map { "E\($0)" }).joinWithSep " var _latestElement\($0): E\($0)! = nil" }).joinWithSeparator("\n") %> - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: <%= i %>, observer: observer, cancel: cancel) + super.init(arity: <%= i %>, observer: observer) } func run() -> Disposable { @@ -49,7 +49,7 @@ class CombineLatestSink<%= i %>_<<%= (Array(1...i).map { "E\($0)" }).joinWithSep }).joinWithSeparator("\n") %> <%= (Array(1...i).map { -" let observer\($0) = CombineLatestObserver(lock: lock, parent: self, index: \($0 - 1), setLatestValue: { (e: E\($0)) -> Void in self._latestElement\($0) = e }, this: subscription\($0))" +" let observer\($0) = CombineLatestObserver(lock: _lock, parent: self, index: \($0 - 1), setLatestValue: { (e: E\($0)) -> Void in self._latestElement\($0) = e }, this: subscription\($0))" }).joinWithSeparator("\n") %> <%= (Array(1...i).map { @@ -83,10 +83,10 @@ class CombineLatest<%= i %><<%= (Array(1...i).map { "E\($0)" }).joinWithSeparato _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = CombineLatestSink<%= i %>_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = CombineLatestSink<%= i %>_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } diff --git a/RxSwift/Observables/Implementations/CombineLatest.swift b/RxSwift/Observables/Implementations/CombineLatest.swift index 300cf2db..5807ebdc 100644 --- a/RxSwift/Observables/Implementations/CombineLatest.swift +++ b/RxSwift/Observables/Implementations/CombineLatest.swift @@ -14,10 +14,12 @@ protocol CombineLatestProtocol : class { func done(index: Int) } -class CombineLatestSink : Sink, CombineLatestProtocol { +class CombineLatestSink + : Sink + , CombineLatestProtocol { typealias Element = O.E - let lock = NSRecursiveLock() + let _lock = NSRecursiveLock() private let _arity: Int private var _numberOfValues = 0 @@ -25,12 +27,12 @@ class CombineLatestSink : Sink, CombineLatestProtocol { private var _hasValue: [Bool] private var _isDone: [Bool] - init(arity: Int, observer: O, cancel: Disposable) { + init(arity: Int, observer: O) { _arity = arity _hasValue = [Bool](count: arity, repeatedValue: false) _isDone = [Bool](count: arity, repeatedValue: false) - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func getResult() throws -> Element { diff --git a/RxSwift/Observables/Implementations/Concat.swift b/RxSwift/Observables/Implementations/Concat.swift index 69136938..c9aca4e8 100644 --- a/RxSwift/Observables/Implementations/Concat.swift +++ b/RxSwift/Observables/Implementations/Concat.swift @@ -12,8 +12,8 @@ import Foundation class ConcatSink : TailRecursiveSink { typealias Element = O.E - override init(observer: O, cancel: Disposable) { - super.init(observer: observer, cancel: cancel) + override init(observer: O) { + super.init(observer: observer) } override func on(event: Event){ @@ -47,11 +47,9 @@ class Concat - (observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ConcatSink(observer: observer, cancel: cancel) - setSink(sink) - - return sink.run(_sources.generate()) + override func run(observer: O) -> Disposable { + let sink = ConcatSink(observer: observer) + sink.disposable = sink.run(_sources.generate()) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Debug.swift b/RxSwift/Observables/Implementations/Debug.swift index f527c2f5..090849cd 100644 --- a/RxSwift/Observables/Implementations/Debug.swift +++ b/RxSwift/Observables/Implementations/Debug.swift @@ -14,9 +14,9 @@ class Debug_ : Sink, ObserverType { private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -45,10 +45,10 @@ class Debug : Producer { _source = source } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { print("[\(_identifier)] subscribed") - let sink = Debug_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + let sink = Debug_(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Deferred.swift b/RxSwift/Observables/Implementations/Deferred.swift index affbd3d2..92b71788 100644 --- a/RxSwift/Observables/Implementations/Deferred.swift +++ b/RxSwift/Observables/Implementations/Deferred.swift @@ -14,9 +14,9 @@ class DeferredSink : Sink, ObserverType { private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -54,10 +54,10 @@ class Deferred : Producer { _observableFactory = observableFactory } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = DeferredSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = DeferredSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } func eval() throws -> Observable { diff --git a/RxSwift/Observables/Implementations/DelaySubscription.swift b/RxSwift/Observables/Implementations/DelaySubscription.swift index 0669bc10..147fd032 100644 --- a/RxSwift/Observables/Implementations/DelaySubscription.swift +++ b/RxSwift/Observables/Implementations/DelaySubscription.swift @@ -8,15 +8,17 @@ import Foundation -class DelaySubscriptionSink : Sink, ObserverType { +class DelaySubscriptionSink + : Sink + , ObserverType { typealias Parent = DelaySubscription typealias E = O.E private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -41,11 +43,12 @@ class DelaySubscription: Producer { _scheduler = scheduler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = DelaySubscriptionSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _scheduler.scheduleRelative((), dueTime: _dueTime) { _ in + override func run(observer: O) -> Disposable { + let sink = DelaySubscriptionSink(parent: self, observer: observer) + sink.disposable = _scheduler.scheduleRelative((), dueTime: _dueTime) { _ in return self._source.subscribe(sink) } + + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/DistinctUntilChanged.swift b/RxSwift/Observables/Implementations/DistinctUntilChanged.swift index 56521765..d0ab70cf 100644 --- a/RxSwift/Observables/Implementations/DistinctUntilChanged.swift +++ b/RxSwift/Observables/Implementations/DistinctUntilChanged.swift @@ -14,9 +14,9 @@ class DistinctUntilChangedSink: Sink, ObserverType { private let _parent: DistinctUntilChanged private var _currentKey: Key? = nil - init(parent: DistinctUntilChanged, observer: O, cancel: Disposable) { + init(parent: DistinctUntilChanged, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -64,9 +64,9 @@ class DistinctUntilChanged: Producer { _comparer = comparer } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = DistinctUntilChangedSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = DistinctUntilChangedSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Do.swift b/RxSwift/Observables/Implementations/Do.swift index 1af070c6..5f163cf6 100644 --- a/RxSwift/Observables/Implementations/Do.swift +++ b/RxSwift/Observables/Implementations/Do.swift @@ -14,9 +14,9 @@ class DoSink : Sink, ObserverType { private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -45,11 +45,9 @@ class Do : Producer { _eventHandler = eventHandler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = DoSink(parent: self, observer: observer, cancel: cancel) - - setSink(sink) - - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = DoSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/ElementAt.swift b/RxSwift/Observables/Implementations/ElementAt.swift index 29f635e2..19401b2c 100644 --- a/RxSwift/Observables/Implementations/ElementAt.swift +++ b/RxSwift/Observables/Implementations/ElementAt.swift @@ -15,11 +15,11 @@ class ElementAtSink : Sink< let _parent: Parent var _i: Int - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent _i = parent._index - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -71,9 +71,9 @@ class ElementAt : Producer { self._throwOnEmpty = throwOnEmpty } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ElementAtSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribeSafe(sink) + override func run(observer: O) -> Disposable { + let sink = ElementAtSink(parent: self, observer: observer) + sink.disposable = _source.subscribeSafe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Filter.swift b/RxSwift/Observables/Implementations/Filter.swift index ad47c6fb..8efda19b 100644 --- a/RxSwift/Observables/Implementations/Filter.swift +++ b/RxSwift/Observables/Implementations/Filter.swift @@ -15,9 +15,9 @@ class FilterSink: Sink, ObserverType { private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -51,9 +51,9 @@ class Filter : Producer { _predicate = predicate } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = FilterSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = FilterSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/FlatMap.swift b/RxSwift/Observables/Implementations/FlatMap.swift index 11ebef1f..f9383df3 100644 --- a/RxSwift/Observables/Implementations/FlatMap.swift +++ b/RxSwift/Observables/Implementations/FlatMap.swift @@ -67,9 +67,9 @@ class FlatMapSink S { @@ -128,8 +128,8 @@ class FlatMapSink : FlatMapSink { - override init(parent: Parent, observer: O, cancel: Disposable) { - super.init(parent: parent, observer: observer, cancel: cancel) + override init(parent: Parent, observer: O) { + super.init(parent: parent, observer: observer) } override func performMap(element: SourceType) throws -> S { @@ -140,8 +140,8 @@ class FlatMapSink1 : FlatMapSink { private var _index = 0 - override init(parent: Parent, observer: O, cancel: Disposable) { - super.init(parent: parent, observer: observer, cancel: cancel) + override init(parent: Parent, observer: O) { + super.init(parent: parent, observer: observer) } override func performMap(element: SourceType) throws -> S { @@ -170,16 +170,18 @@ class FlatMap: Producer { _selector1 = nil } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { + let sink: FlatMapSink if let _ = _selector1 { - let sink = FlatMapSink1(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + sink = FlatMapSink1(parent: self, observer: observer) } else { - let sink = FlatMapSink2(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + sink = FlatMapSink2(parent: self, observer: observer) } + + let subscription = sink.run() + sink.disposable = subscription + + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Generate.swift b/RxSwift/Observables/Implementations/Generate.swift index 4e6a51c1..1c2f6ba2 100644 --- a/RxSwift/Observables/Implementations/Generate.swift +++ b/RxSwift/Observables/Implementations/Generate.swift @@ -15,10 +15,10 @@ class GenerateSink : Sink { private var _state: S - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent _state = parent._initialState - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -63,9 +63,9 @@ class Generate : Producer { super.init() } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = GenerateSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = GenerateSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Map.swift b/RxSwift/Observables/Implementations/Map.swift index 5781ed60..e7817cbe 100644 --- a/RxSwift/Observables/Implementations/Map.swift +++ b/RxSwift/Observables/Implementations/Map.swift @@ -15,9 +15,9 @@ class MapSink : Sink, ObserverType { private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func performMap(element: SourceType) throws -> ResultType { @@ -50,8 +50,8 @@ class MapSink : Sink, ObserverType { class MapSink1 : MapSink { typealias ResultType = O.E - override init(parent: Map, observer: O, cancel: Disposable) { - super.init(parent: parent, observer: observer, cancel: cancel) + override init(parent: Map, observer: O) { + super.init(parent: parent, observer: observer) } override func performMap(element: SourceType) throws -> ResultType { @@ -64,8 +64,8 @@ class MapSink2 : MapSink { private var _index = 0 - override init(parent: Map, observer: O, cancel: Disposable) { - super.init(parent: parent, observer: observer, cancel: cancel) + override init(parent: Map, observer: O) { + super.init(parent: parent, observer: observer) } override func performMap(element: SourceType) throws -> ResultType { return try _parent._selector2!(element, try incrementChecked(&_index)) @@ -93,16 +93,16 @@ class Map: Producer { _selector1 = nil } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { if let _ = _selector1 { - let sink = MapSink1(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + let sink = MapSink1(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } else { - let sink = MapSink2(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + let sink = MapSink2(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } diff --git a/RxSwift/Observables/Implementations/Merge.swift b/RxSwift/Observables/Implementations/Merge.swift index 65761898..a0b996ba 100644 --- a/RxSwift/Observables/Implementations/Merge.swift +++ b/RxSwift/Observables/Implementations/Merge.swift @@ -10,46 +10,59 @@ import Foundation // sequential -class MergeSinkIter : ObserverType { +class MergeSinkIter + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = O.E typealias DisposeKey = Bag.KeyType typealias Parent = MergeSink private let _parent: Parent private let _disposeKey: DisposeKey - + + var _lock: NSRecursiveLock { + return _parent._lock + } + init(parent: Parent, disposeKey: DisposeKey) { _parent = parent _disposeKey = disposeKey } func on(event: Event) { - _parent._lock.performLocked { - switch event { - case .Next: - _parent.observer?.on(event) - case .Error: - _parent.observer?.on(event) + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next: + _parent.observer?.on(event) + case .Error: + _parent.observer?.on(event) + _parent.dispose() + case .Completed: + _parent._group.removeDisposable(_disposeKey) + + if _parent._stopped && _parent._group.count == 1 { + _parent.observer?.on(.Completed) _parent.dispose() - case .Completed: - _parent._group.removeDisposable(_disposeKey) - - if _parent._stopped && _parent._group.count == 1 { - _parent.observer?.on(.Completed) - _parent.dispose() - } } } } } -class MergeSink : Sink, ObserverType { +class MergeSink + : Sink + , ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = S typealias Parent = Merge private let _parent: Parent - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _stopped = false @@ -57,10 +70,10 @@ class MergeSink private let _group = CompositeDisposable() private let _sourceSubscription = SingleAssignmentDisposable() - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -73,8 +86,7 @@ class MergeSink } func on(event: Event) { - switch event { - case .Next(let value): + if case .Next(let value) = event { let innerSubscription = SingleAssignmentDisposable() let maybeKey = _group.addDisposable(innerSubscription) @@ -83,22 +95,29 @@ class MergeSink let disposable = value.asObservable().subscribe(observer) innerSubscription.disposable = disposable } + + return + } + + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next: + rxFatalError("Next should have been handled") case .Error(let error): - _lock.performLocked { - observer?.on(.Error(error)) + observer?.on(.Error(error)) + dispose() + case .Completed: + _stopped = true + + if _group.count == 1 { + observer?.on(.Completed) dispose() } - case .Completed: - _lock.performLocked { - _stopped = true - - if _group.count == 1 { - observer?.on(.Completed) - dispose() - } - else { - _sourceSubscription.dispose() - } + else { + _sourceSubscription.dispose() } } } @@ -106,13 +125,20 @@ class MergeSink // concurrent -class MergeConcurrentSinkIter : ObserverType { +class MergeConcurrentSinkIter + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = O.E typealias DisposeKey = Bag.KeyType typealias Parent = MergeConcurrentSink private let _parent: Parent private let _disposeKey: DisposeKey + + var _lock: NSRecursiveLock { + return _parent._lock + } init(parent: Parent, disposeKey: DisposeKey) { _parent = parent @@ -120,42 +146,48 @@ class MergeConcurrentSinkIter) { - _parent._lock.performLocked { - switch event { - case .Next: - _parent.observer?.on(event) - case .Error: - _parent.observer?.on(event) - _parent.dispose() - case .Completed: - _parent._group.removeDisposable(_disposeKey) - let queue = _parent._queue - if queue.value.count > 0 { - let s = queue.value.dequeue() - _parent.subscribe(s, group: _parent._group) - } - else { - _parent._activeCount = _parent._activeCount - 1 - - if _parent._stopped && _parent._activeCount == 0 { - _parent.observer?.on(.Completed) - _parent.dispose() - } + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next: + _parent.observer?.on(event) + case .Error: + _parent.observer?.on(event) + _parent.dispose() + case .Completed: + _parent._group.removeDisposable(_disposeKey) + let queue = _parent._queue + if queue.value.count > 0 { + let s = queue.value.dequeue() + _parent.subscribe(s, group: _parent._group) + } + else { + _parent._activeCount = _parent._activeCount - 1 + + if _parent._stopped && _parent._activeCount == 0 { + _parent.observer?.on(.Completed) + _parent.dispose() } } } } } -class MergeConcurrentSink : Sink, ObserverType { +class MergeConcurrentSink + : Sink + , ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = S typealias Parent = Merge typealias QueueType = Queue private let _parent: Parent - private let _lock = NSRecursiveLock() - + let _lock = NSRecursiveLock() + // state private var _stopped = false private var _activeCount = 0 @@ -164,11 +196,11 @@ class MergeConcurrentSink Disposable { @@ -193,39 +225,38 @@ class MergeConcurrentSink) { + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { switch event { case .Next(let value): - let subscribe = _lock.calculateLocked { () -> Bool in - if _activeCount < _parent._maxConcurrent { - _activeCount += 1 - return true - } - else { - _queue.value.enqueue(value) - return false - } + let subscribe: Bool + if _activeCount < _parent._maxConcurrent { + _activeCount += 1 + subscribe = true } - + else { + _queue.value.enqueue(value) + subscribe = false + } + if subscribe { self.subscribe(value, group: _group) } case .Error(let error): - _lock.performLocked { - observer?.on(.Error(error)) + observer?.on(.Error(error)) + dispose() + case .Completed: + if _activeCount == 0 { + observer?.on(.Completed) dispose() } - case .Completed: - _lock.performLocked { - if _activeCount == 0 { - observer?.on(.Completed) - dispose() - } - else { - _sourceSubscription.dispose() - } - - _stopped = true + else { + _sourceSubscription.dispose() } + + _stopped = true } } } @@ -239,16 +270,16 @@ class Merge : Producer { _maxConcurrent = maxConcurrent } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { if _maxConcurrent > 0 { - let sink = MergeConcurrentSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + let sink = MergeConcurrentSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } else { - let sink = MergeSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + let sink = MergeSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Multicast.swift b/RxSwift/Observables/Implementations/Multicast.swift index f63d14b5..770d5e8d 100644 --- a/RxSwift/Observables/Implementations/Multicast.swift +++ b/RxSwift/Observables/Implementations/Multicast.swift @@ -15,9 +15,9 @@ class MulticastSink: Sink, ObserverType { private let _parent: MutlicastType - init(parent: MutlicastType, observer: O, cancel: Disposable) { + init(parent: MutlicastType, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -63,9 +63,9 @@ class Multicast: Producer { _selector = selector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = MulticastSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = MulticastSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/ObserveOn.swift b/RxSwift/Observables/Implementations/ObserveOn.swift index ec2d12f1..5eb1298d 100644 --- a/RxSwift/Observables/Implementations/ObserveOn.swift +++ b/RxSwift/Observables/Implementations/ObserveOn.swift @@ -21,10 +21,10 @@ class ObserveOn : Producer { #endif } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ObserveOnSink(scheduler: scheduler, observer: observer, cancel: cancel) - setSink(sink) - return source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = ObserveOnSink(scheduler: scheduler, observer: observer) + sink._subscription.disposable = source.subscribe(sink) + return sink } #if TRACE_RESOURCES @@ -44,31 +44,30 @@ enum ObserveOnState : Int32 { class ObserveOnSink : ObserverBase { typealias E = O.E - var cancel: Disposable - - var lock = SpinLock() - - let scheduler: ImmediateSchedulerType - var observer: O? - - var state = ObserveOnState.Stopped - - var queue = Queue>(capacity: 10) - let scheduleDisposable = SerialDisposable() - - init(scheduler: ImmediateSchedulerType, observer: O, cancel: Disposable) { - self.cancel = cancel - self.scheduler = scheduler - self.observer = observer + let _scheduler: ImmediateSchedulerType + + var _lock = SpinLock() + + // state + var _state = ObserveOnState.Stopped + var _observer: O? + var _queue = Queue>(capacity: 10) + + let _scheduleDisposable = SerialDisposable() + let _subscription = SingleAssignmentDisposable() + + init(scheduler: ImmediateSchedulerType, observer: O) { + _scheduler = scheduler + _observer = observer } override func onCore(event: Event) { - let shouldStart = lock.calculateLocked { () -> Bool in - self.queue.enqueue(event) + let shouldStart = _lock.calculateLocked { () -> Bool in + self._queue.enqueue(event) - switch self.state { + switch self._state { case .Stopped: - self.state = .Running + self._state = .Running return true case .Running: return false @@ -76,18 +75,18 @@ class ObserveOnSink : ObserverBase { } if shouldStart { - scheduleDisposable.disposable = self.scheduler.scheduleRecursive((), action: self.run) + _scheduleDisposable.disposable = self._scheduler.scheduleRecursive((), action: self.run) } } func run(state: Void, recurse: Void -> Void) { - let (nextEvent, observer) = self.lock.calculateLocked { () -> (Event?, O?) in - if self.queue.count > 0 { - return (self.queue.dequeue(), self.observer) + let (nextEvent, observer) = self._lock.calculateLocked { () -> (Event?, O?) in + if self._queue.count > 0 { + return (self._queue.dequeue(), self._observer) } else { - self.state = .Stopped - return (nil, self.observer) + self._state = .Stopped + return (nil, self._observer) } } @@ -101,32 +100,33 @@ class ObserveOnSink : ObserverBase { return } - let shouldContinue = self.lock.calculateLocked { () -> Bool in - if self.queue.count > 0 { - return true - } - else { - self.state = .Stopped - return false - } - } + let shouldContinue = _shouldContinue_synchronized() if shouldContinue { recurse() } } + + func _shouldContinue_synchronized() -> Bool { + _lock.lock(); defer { _lock.unlock() } // { + if self._queue.count > 0 { + return true + } + else { + self._state = .Stopped + return false + } + // } + } override func dispose() { super.dispose() - - let toDispose = lock.calculateLocked { () -> Disposable in - let originalCancel = self.cancel - self.cancel = NopDisposable.instance - self.scheduleDisposable.dispose() - self.observer = nil - return originalCancel - } - - toDispose.dispose() + + _subscription.dispose() + _scheduleDisposable.dispose() + + _lock.lock(); defer { _lock.unlock() } // { + _observer = nil + // } } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift b/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift index 3fa66efd..7d3f5675 100644 --- a/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift +++ b/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift @@ -22,12 +22,9 @@ class ObserveOnSerialDispatchQueueSink : ObserverBase { let scheduler: SerialDispatchQueueScheduler let observer: O - var disposeLock = SpinLock() + let subscription = SingleAssignmentDisposable() - var cancel: Disposable - - init(scheduler: SerialDispatchQueueScheduler, observer: O, cancel: Disposable) { - self.cancel = cancel + init(scheduler: SerialDispatchQueueScheduler, observer: O) { self.scheduler = scheduler self.observer = observer super.init() @@ -47,14 +44,8 @@ class ObserveOnSerialDispatchQueueSink : ObserverBase { override func dispose() { super.dispose() - - let toDispose = disposeLock.calculateLocked { () -> Disposable in - let originalCancel = self.cancel - self.cancel = NopDisposable.instance - return originalCancel - } - - toDispose.dispose() + + subscription.dispose() } } @@ -72,10 +63,10 @@ class ObserveOnSerialDispatchQueue : Producer { #endif } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ObserveOnSerialDispatchQueueSink(scheduler: scheduler, observer: observer, cancel: cancel) - setSink(sink) - return source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = ObserveOnSerialDispatchQueueSink(scheduler: scheduler, observer: observer) + sink.subscription.disposable = source.subscribe(sink) + return sink } #if TRACE_RESOURCES diff --git a/RxSwift/Observables/Implementations/Producer.swift b/RxSwift/Observables/Implementations/Producer.swift index 63c38c76..8b8098a8 100644 --- a/RxSwift/Observables/Implementations/Producer.swift +++ b/RxSwift/Observables/Implementations/Producer.swift @@ -14,30 +14,17 @@ class Producer : Observable { } override func subscribe(observer: O) -> Disposable { - let sink = SingleAssignmentDisposable() - let subscription = SingleAssignmentDisposable() - - let d = BinaryDisposable(sink, subscription) - - let setSink: (Disposable) -> Void = { d in sink.disposable = d } - if !CurrentThreadScheduler.isScheduleRequired { - let disposable = run(observer, cancel: subscription, setSink: setSink) - - subscription.disposable = disposable + return run(observer) } else { - CurrentThreadScheduler.instance.schedule(sink) { sink in - let disposable = self.run(observer, cancel: subscription, setSink: setSink) - subscription.disposable = disposable - return NopDisposable.instance + return CurrentThreadScheduler.instance.schedule(()) { _ in + return self.run(observer) } } - - return d } - func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + func run(observer: O) -> Disposable { abstractMethod() } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Range.swift b/RxSwift/Observables/Implementations/Range.swift index ded21856..8093416a 100644 --- a/RxSwift/Observables/Implementations/Range.swift +++ b/RxSwift/Observables/Implementations/Range.swift @@ -27,10 +27,10 @@ class RangeProducer<_CompilerWorkaround> : Producer { _scheduler = scheduler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = RangeSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = RangeSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -39,9 +39,9 @@ class RangeSink<_CompilerWorkaround, O: ObserverType where O.E == Int> : Sink private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { diff --git a/RxSwift/Observables/Implementations/Reduce.swift b/RxSwift/Observables/Implementations/Reduce.swift index e8653d85..3276b326 100644 --- a/RxSwift/Observables/Implementations/Reduce.swift +++ b/RxSwift/Observables/Implementations/Reduce.swift @@ -15,11 +15,11 @@ class ReduceSink : Sink, Observe private let _parent: Parent private var _accumulation: AccumulateType - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent _accumulation = parent._seed - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -66,9 +66,9 @@ class Reduce : Producer { _mapResult = mapResult } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ReduceSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = ReduceSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/RefCount.swift b/RxSwift/Observables/Implementations/RefCount.swift index eacd4ac0..4216aefa 100644 --- a/RxSwift/Observables/Implementations/RefCount.swift +++ b/RxSwift/Observables/Implementations/RefCount.swift @@ -8,21 +8,23 @@ import Foundation -class RefCountSink : Sink, ObserverType { +class RefCountSink + : Sink + , ObserverType { typealias Element = O.E typealias Parent = RefCount private let _parent: Parent - - init(parent: Parent, observer: O, cancel: Disposable) { + + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { let subscription = _parent._source.subscribeSafe(self) - _parent._lock.performLocked { + _parent._lock.lock(); defer { _parent._lock.unlock() } // { if _parent._count == 0 { _parent._count = 1 _parent._connectableSubscription = _parent._source.connect() @@ -30,11 +32,11 @@ class RefCountSink: Producer { _source = source } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = RefCountSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = RefCountSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Repeat.swift b/RxSwift/Observables/Implementations/Repeat.swift index 33621d68..8655d929 100644 --- a/RxSwift/Observables/Implementations/Repeat.swift +++ b/RxSwift/Observables/Implementations/Repeat.swift @@ -17,10 +17,11 @@ class RepeatElement : Producer { _scheduler = scheduler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = RepeatElementSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = RepeatElementSink(parent: self, observer: observer) + sink.disposable = sink.run() + + return sink } } @@ -29,9 +30,9 @@ class RepeatElementSink : Sink { private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { diff --git a/RxSwift/Observables/Implementations/Sample.swift b/RxSwift/Observables/Implementations/Sample.swift index 459a3484..703b86e1 100644 --- a/RxSwift/Observables/Implementations/Sample.swift +++ b/RxSwift/Observables/Implementations/Sample.swift @@ -8,57 +8,70 @@ import Foundation -class SamplerSink : ObserverType { +class SamplerSink + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = SampleType typealias Parent = SampleSequenceSink private let _parent: Parent + + var _lock: NSRecursiveLock { + return _parent._lock + } init(parent: Parent) { _parent = parent } func on(event: Event) { - _parent._lock.performLocked { - switch event { - case .Next: - if let element = _parent._element { - if _parent._parent._onlyNew { - _parent._element = nil - } - - _parent.observer?.on(.Next(element)) - } + synchronizedOn(event) + } - if _parent._atEnd { - _parent.observer?.on(.Completed) - _parent.dispose() - } - case .Error(let e): - _parent.observer?.on(.Error(e)) - _parent.dispose() - case .Completed: - if let element = _parent._element { + func _synchronized_on(event: Event) { + switch event { + case .Next: + if let element = _parent._element { + if _parent._parent._onlyNew { _parent._element = nil - _parent.observer?.on(.Next(element)) - } - if _parent._atEnd { - _parent.observer?.on(.Completed) - _parent.dispose() } + + _parent.observer?.on(.Next(element)) + } + + if _parent._atEnd { + _parent.observer?.on(.Completed) + _parent.dispose() + } + case .Error(let e): + _parent.observer?.on(.Error(e)) + _parent.dispose() + case .Completed: + if let element = _parent._element { + _parent._element = nil + _parent.observer?.on(.Next(element)) + } + if _parent._atEnd { + _parent.observer?.on(.Completed) + _parent.dispose() } } } } -class SampleSequenceSink : Sink, ObserverType { +class SampleSequenceSink + : Sink + , ObserverType + , LockOwnerType + , SynchronizedOnType { typealias Element = O.E typealias Parent = Sample private let _parent: Parent - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _element = nil as Element? @@ -66,30 +79,32 @@ class SampleSequenceSink : Sink, ObserverType { private let _sourceSubscription = SingleAssignmentDisposable() - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { _sourceSubscription.disposable = _parent._source.subscribe(self) let samplerSubscription = _parent._sampler.subscribe(SamplerSink(parent: self)) - return CompositeDisposable(_sourceSubscription, samplerSubscription) + return StableCompositeDisposable.create(_sourceSubscription, samplerSubscription) } func on(event: Event) { - _lock.performLocked { - switch event { - case .Next(let element): - _element = element - case .Error: - observer?.on(event) - dispose() - case .Completed: - _atEnd = true - _sourceSubscription.dispose() - } + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next(let element): + _element = element + case .Error: + observer?.on(event) + dispose() + case .Completed: + _atEnd = true + _sourceSubscription.dispose() } } @@ -106,9 +121,9 @@ class Sample : Producer { _onlyNew = onlyNew } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = SampleSequenceSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = SampleSequenceSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Scan.swift b/RxSwift/Observables/Implementations/Scan.swift index 58a7d720..9f0f5feb 100644 --- a/RxSwift/Observables/Implementations/Scan.swift +++ b/RxSwift/Observables/Implementations/Scan.swift @@ -15,10 +15,10 @@ class ScanSink private let _parent: Parent private var _accumulate: Accumulate - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent _accumulate = parent._seed - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -56,9 +56,9 @@ class Scan: Producer { _accumulator = accumulator } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ScanSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = ScanSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Sink.swift b/RxSwift/Observables/Implementations/Sink.swift index 62851338..e6ce7278 100644 --- a/RxSwift/Observables/Implementations/Sink.swift +++ b/RxSwift/Observables/Implementations/Sink.swift @@ -8,14 +8,12 @@ import Foundation -class Sink : Disposable { +class Sink : SingleAssignmentDisposable { private var _lock = SpinLock() // state private var _observer: O? - private var _cancel: Disposable - private var _disposed: Bool = false - + var observer: O? { get { _lock.lock(); defer { _lock.unlock() } @@ -23,32 +21,24 @@ class Sink : Disposable { } } - init(observer: O, cancel: Disposable) { + init(observer: O) { #if TRACE_RESOURCES OSAtomicIncrement32(&resourceCount) #endif _observer = observer - _cancel = cancel } - private func _disposeInternal() -> Disposable? { + private func _disposeObserver() { _lock.lock(); defer { _lock.unlock() } - if _disposed { - return nil - } - - let cancel = _cancel - - _disposed = true _observer = nil - _cancel = NopDisposable.instance - - return cancel } - func dispose() { - _disposeInternal()?.dispose() + override func dispose() { + if !disposed { + _disposeObserver() + } + super.dispose() } deinit { diff --git a/RxSwift/Observables/Implementations/Skip.swift b/RxSwift/Observables/Implementations/Skip.swift index 65df2212..8d4ddc53 100644 --- a/RxSwift/Observables/Implementations/Skip.swift +++ b/RxSwift/Observables/Implementations/Skip.swift @@ -18,10 +18,10 @@ class SkipCountSink : Sin var remaining: Int - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { self.parent = parent self.remaining = parent.count - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -54,10 +54,11 @@ class SkipCount: Producer { self.count = count } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = SkipCountSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = SkipCountSink(parent: self, observer: observer) + sink.disposable = source.subscribe(sink) + + return sink } } @@ -72,9 +73,9 @@ class SkipTimeSink) { @@ -121,9 +122,9 @@ class SkipTime: Producer { self.duration = duration } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = SkipTimeSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = SkipTimeSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/SkipUntil.swift b/RxSwift/Observables/Implementations/SkipUntil.swift index 05882d29..66448416 100644 --- a/RxSwift/Observables/Implementations/SkipUntil.swift +++ b/RxSwift/Observables/Implementations/SkipUntil.swift @@ -8,20 +8,27 @@ import Foundation -class SkipUntilSinkOther : ObserverType { +class SkipUntilSinkOther + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias Parent = SkipUntilSink typealias E = Other private let _parent: Parent + + var _lock: NSRecursiveLock { + return _parent._lock + } - private let _singleAssignmentDisposable = SingleAssignmentDisposable() - - var disposable: Disposable { + private let _subscription = SingleAssignmentDisposable() + + var subscription: Disposable { get { abstractMethod() } set { - _singleAssignmentDisposable.disposable = newValue + _subscription.disposable = newValue } } @@ -33,19 +40,19 @@ class SkipUntilSinkOther) { + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { switch event { case .Next: - _parent._lock.performLocked { - _parent._forwardElements = true - _singleAssignmentDisposable.dispose() - } + _parent._forwardElements = true + _subscription.dispose() case .Error(let e): - _parent._lock.performLocked { - _parent.observer?.onError(e) - _parent.dispose() - } + _parent.observer?.onError(e) + _parent.dispose() case .Completed: - _singleAssignmentDisposable.dispose() + _subscription.dispose() } } @@ -58,46 +65,43 @@ class SkipUntilSinkOther : Sink, ObserverType { +class SkipUntilSink + : Sink + , ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = ElementType typealias Parent = SkipUntil - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() private let _parent: Parent private var _forwardElements = false - private let _singleAssignmentDisposable = SingleAssignmentDisposable() - - var disposable: Disposable { - get { - abstractMethod() - } - set { - _singleAssignmentDisposable.disposable = newValue - } - } - - init(parent: Parent, observer: O, cancel: Disposable) { + private let _sourceSubscription = SingleAssignmentDisposable() + + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { - _lock.performLocked { - switch event { - case .Next: - if _forwardElements { - observer?.on(event) - } - case .Error: + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next: + if _forwardElements { observer?.on(event) - dispose() - case .Completed: - if _forwardElements { - observer?.on(event) - } - _singleAssignmentDisposable.dispose() } + case .Error: + observer?.on(event) + dispose() + case .Completed: + if _forwardElements { + observer?.on(event) + } + _sourceSubscription.dispose() } } @@ -105,10 +109,10 @@ class SkipUntilSink: Producer { _other = other } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = SkipUntilSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = SkipUntilSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } diff --git a/RxSwift/Observables/Implementations/SkipWhile.swift b/RxSwift/Observables/Implementations/SkipWhile.swift index 8261f0eb..65af9476 100644 --- a/RxSwift/Observables/Implementations/SkipWhile.swift +++ b/RxSwift/Observables/Implementations/SkipWhile.swift @@ -14,9 +14,9 @@ class SkipWhileSink : Sin private let _parent: Parent private var _running = false - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -51,9 +51,9 @@ class SkipWhileSinkWithIndex) { @@ -100,16 +100,16 @@ class SkipWhile: Producer { _predicateWithIndex = predicate } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { if let _ = _predicate { - let sink = SkipWhileSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + let sink = SkipWhileSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } else { - let sink = SkipWhileSinkWithIndex(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + let sink = SkipWhileSinkWithIndex(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } } diff --git a/RxSwift/Observables/Implementations/StartWith.swift b/RxSwift/Observables/Implementations/StartWith.swift index 450c1189..f2848409 100644 --- a/RxSwift/Observables/Implementations/StartWith.swift +++ b/RxSwift/Observables/Implementations/StartWith.swift @@ -18,7 +18,7 @@ class StartWith: Producer { super.init() } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { for e in elements { observer.on(.Next(e)) } diff --git a/RxSwift/Observables/Implementations/SubscribeOn.swift b/RxSwift/Observables/Implementations/SubscribeOn.swift index e1419d40..a919af00 100644 --- a/RxSwift/Observables/Implementations/SubscribeOn.swift +++ b/RxSwift/Observables/Implementations/SubscribeOn.swift @@ -14,9 +14,9 @@ class SubscribeOnSink : S let parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { self.parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -52,9 +52,9 @@ class SubscribeOn : Producer { self.scheduler = scheduler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = SubscribeOnSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = SubscribeOnSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Switch.swift b/RxSwift/Observables/Implementations/Switch.swift index 1f48d33c..db5b7662 100644 --- a/RxSwift/Observables/Implementations/Switch.swift +++ b/RxSwift/Observables/Implementations/Switch.swift @@ -8,7 +8,11 @@ import Foundation -class SwitchSink : Sink, ObserverType { +class SwitchSink + : Sink + , ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = S typealias Parent = Switch @@ -16,34 +20,36 @@ class SwitchSink private let _innerSubscription: SerialDisposable = SerialDisposable() private let _parent: Parent - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _stopped = false private var _latest = 0 private var _hasLatest = false - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { let subscription = _parent._sources.subscribe(self) _subscriptions.disposable = subscription - return CompositeDisposable(_subscriptions, _innerSubscription) + return StableCompositeDisposable.create(_subscriptions, _innerSubscription) } func on(event: Event) { + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { switch event { case .Next(let observable): - let latest: Int = _lock.calculateLocked { - _hasLatest = true - _latest = _latest &+ 1 - return _latest - } - + _hasLatest = true + _latest = _latest &+ 1 + let latest = _latest + let d = SingleAssignmentDisposable() _innerSubscription.disposable = d @@ -51,33 +57,36 @@ class SwitchSink let disposable = observable.asObservable().subscribe(observer) d.disposable = disposable case .Error(let error): - _lock.performLocked { - observer?.on(.Error(error)) - dispose() - } + observer?.on(.Error(error)) + dispose() case .Completed: - _lock.performLocked { - _stopped = true - - _subscriptions.dispose() - - if !_hasLatest { - observer?.on(.Completed) - dispose() - } + _stopped = true + + _subscriptions.dispose() + + if !_hasLatest { + observer?.on(.Completed) + dispose() } } } } -class SwitchSinkIter : ObserverType { +class SwitchSinkIter + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = O.E typealias Parent = SwitchSink private let _parent: Parent private let _id: Int private let _self: Disposable - + + var _lock: NSRecursiveLock { + return _parent._lock + } + init(parent: Parent, id: Int, _self: Disposable) { _parent = parent _id = id @@ -85,32 +94,33 @@ class SwitchSinkIter) { - return _parent._lock.calculateLocked { - - switch event { - case .Next: break - case .Error, .Completed: - _self.dispose() - } - - if _parent._latest != _id { - return - } - - let observer = _parent.observer - - switch event { - case .Next: - observer?.on(event) - case .Error: + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next: break + case .Error, .Completed: + _self.dispose() + } + + if _parent._latest != _id { + return + } + + let observer = _parent.observer + + switch event { + case .Next: + observer?.on(event) + case .Error: + observer?.on(event) + _parent.dispose() + case .Completed: + _parent._hasLatest = false + if _parent._stopped { observer?.on(event) _parent.dispose() - case .Completed: - _parent._hasLatest = false - if _parent._stopped { - observer?.on(event) - _parent.dispose() - } } } } @@ -123,9 +133,9 @@ class Switch : Producer { _sources = sources } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = SwitchSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = SwitchSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Take.swift b/RxSwift/Observables/Implementations/Take.swift index 9208e618..24ef5231 100644 --- a/RxSwift/Observables/Implementations/Take.swift +++ b/RxSwift/Observables/Implementations/Take.swift @@ -18,10 +18,10 @@ class TakeCountSink : Sin private var _remaining: Int - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent _remaining = parent._count - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -61,48 +61,54 @@ class TakeCount: Producer { _count = count } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = TakeCountSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = TakeCountSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } // time version -class TakeTimeSink : Sink, ObserverType { +class TakeTimeSink + : Sink + , LockOwnerType + , ObserverType + , SynchronizedOnType { typealias Parent = TakeTime typealias E = ElementType private let _parent: Parent - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { - _lock.performLocked { - switch event { - case .Next(let value): - observer?.on(.Next(value)) - case .Error: - observer?.on(event) - dispose() - case .Completed: - observer?.on(event) - dispose() - } + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next(let value): + observer?.on(.Next(value)) + case .Error: + observer?.on(event) + dispose() + case .Completed: + observer?.on(event) + dispose() } } func tick() { - _lock.performLocked { - observer?.on(.Completed) - dispose() - } + _lock.lock(); defer { _lock.unlock() } + + observer?.on(.Completed) + dispose() } func run() -> Disposable { @@ -130,9 +136,9 @@ class TakeTime: Producer { _duration = duration } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = TakeTimeSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = TakeTimeSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/TakeLast.swift b/RxSwift/Observables/Implementations/TakeLast.swift index 34edb8a2..1a14e2e6 100644 --- a/RxSwift/Observables/Implementations/TakeLast.swift +++ b/RxSwift/Observables/Implementations/TakeLast.swift @@ -17,10 +17,10 @@ class TakeLastSink : Sink private var _elements: Queue - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent _elements = Queue(capacity: parent._count + 1) - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -55,9 +55,9 @@ class TakeLast: Producer { _count = count } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = TakeLastSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = TakeLastSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/TakeUntil.swift b/RxSwift/Observables/Implementations/TakeUntil.swift index b15020b9..21f492d1 100644 --- a/RxSwift/Observables/Implementations/TakeUntil.swift +++ b/RxSwift/Observables/Implementations/TakeUntil.swift @@ -8,11 +8,18 @@ import Foundation -class TakeUntilSinkOther : ObserverType { +class TakeUntilSinkOther + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias Parent = TakeUntilSink typealias E = Other private let _parent: Parent + + var _lock: NSRecursiveLock { + return _parent._lock + } private let _singleAssignmentDisposable = SingleAssignmentDisposable() @@ -33,18 +40,20 @@ class TakeUntilSinkOther) { - _parent._lock.performLocked { - switch event { - case .Next: - _parent.observer?.on(.Completed) - _parent.dispose() - case .Error(let e): - _parent.observer?.on(.Error(e)) - _parent.dispose() - case .Completed: - _parent._open = true - _singleAssignmentDisposable.dispose() - } + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case .Next: + _parent.observer?.on(.Completed) + _parent.dispose() + case .Error(let e): + _parent.observer?.on(.Error(e)) + _parent.dispose() + case .Completed: + _parent._open = true + _singleAssignmentDisposable.dispose() } } @@ -55,43 +64,40 @@ class TakeUntilSinkOther : Sink, ObserverType { +class TakeUntilSink + : Sink + , LockOwnerType + , ObserverType + , SynchronizedOnType { typealias E = ElementType typealias Parent = TakeUntil private let _parent: Parent - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _open = false - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { switch event { case .Next: - if _open { - observer?.on(event) - } - else { - _lock.performLocked { - observer?.on(event) - } - } + observer?.on(event) case .Error: - _lock.performLocked { - observer?.on(event) - dispose() - } + observer?.on(event) + dispose() case .Completed: - _lock.performLocked { - observer?.on(event) - dispose() - } + observer?.on(event) + dispose() } } @@ -101,7 +107,7 @@ class TakeUntilSink: Producer { _other = other } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = TakeUntilSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = TakeUntilSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/TakeWhile.swift b/RxSwift/Observables/Implementations/TakeWhile.swift index 22c5f99a..80dadf94 100644 --- a/RxSwift/Observables/Implementations/TakeWhile.swift +++ b/RxSwift/Observables/Implementations/TakeWhile.swift @@ -8,7 +8,9 @@ import Foundation -class TakeWhileSink : Sink, ObserverType { +class TakeWhileSink + : Sink + , ObserverType { typealias Parent = TakeWhile typealias Element = ElementType @@ -16,9 +18,9 @@ class TakeWhileSink : Sin private var _running = true - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -50,7 +52,9 @@ class TakeWhileSink : Sin } -class TakeWhileSinkWithIndex : Sink, ObserverType { +class TakeWhileSinkWithIndex + : Sink + , ObserverType { typealias Parent = TakeWhile typealias Element = ElementType @@ -59,9 +63,9 @@ class TakeWhileSinkWithIndex) { @@ -114,15 +118,15 @@ class TakeWhile: Producer { _predicateWithIndex = predicate } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { if let _ = _predicate { - let sink = TakeWhileSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + let sink = TakeWhileSink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } else { - let sink = TakeWhileSinkWithIndex(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + let sink = TakeWhileSinkWithIndex(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Throttle.swift b/RxSwift/Observables/Implementations/Throttle.swift index 5ca0642f..e89cf908 100644 --- a/RxSwift/Observables/Implementations/Throttle.swift +++ b/RxSwift/Observables/Implementations/Throttle.swift @@ -8,13 +8,17 @@ import Foundation -class ThrottleSink : Sink, ObserverType { +class ThrottleSink + : Sink + , ObserverType + , LockOwnerType + , SynchronizedOnType { typealias Element = O.E typealias ParentType = Throttle private let _parent: ParentType - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _id = 0 as UInt64 @@ -22,81 +26,60 @@ class ThrottleSink : Sink, Observe let cancellable = SerialDisposable() - init(parent: ParentType, observer: O, cancel: Disposable) { + init(parent: ParentType, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { let subscription = _parent._source.subscribe(self) - return CompositeDisposable(subscription, cancellable) + return StableCompositeDisposable.create(subscription, cancellable) } func on(event: Event) { + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { switch event { - case .Next: - break - case .Error, .Completed: - cancellable.dispose() - } - - let latestId = _lock.calculateLocked { () -> UInt64 in - let observer = self.observer - - let oldValue = _value - + case .Next(let element): _id = _id &+ 1 - - switch event { - case .Next(let element): - _value = element - case .Error: - _value = nil - observer?.on(event) - dispose() - case .Completed: - _value = nil - if let value = oldValue { - observer?.on(.Next(value)) - } - observer?.on(.Completed) - dispose() - } - - return _id - } - - - switch event { - case .Next: - let d = SingleAssignmentDisposable() - self.cancellable.disposable = d + let currentId = _id + _value = element + let scheduler = _parent._scheduler let dueTime = _parent._dueTime - - let disposeTimer = scheduler.scheduleRelative(latestId, dueTime: dueTime) { (id) in - self.propagate() - return NopDisposable.instance + + let d = SingleAssignmentDisposable() + self.cancellable.disposable = d + d.disposable = scheduler.scheduleRelative(currentId, dueTime: dueTime, action: self.propagate) + case .Error: + _value = nil + observer?.on(event) + dispose() + case .Completed: + if let value = _value { + _value = nil + observer?.on(.Next(value)) } - - d.disposable = disposeTimer - default: break + observer?.on(.Completed) + dispose() } } - func propagate() { - let originalValue: Element? = _lock.calculateLocked { + func propagate(currentId: UInt64) -> Disposable { + _lock.lock(); defer { _lock.unlock() } // { let originalValue = _value - _value = nil - return originalValue - } - - if let value = originalValue { - observer?.on(.Next(value)) - } + + if let value = originalValue where _id == currentId { + _value = nil + observer?.on(.Next(value)) + } + // } + return NopDisposable.instance } } @@ -112,10 +95,10 @@ class Throttle : Producer { _scheduler = scheduler } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ThrottleSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ThrottleSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Timer.swift b/RxSwift/Observables/Implementations/Timer.swift index 35f2839f..f6b7d724 100644 --- a/RxSwift/Observables/Implementations/Timer.swift +++ b/RxSwift/Observables/Implementations/Timer.swift @@ -13,9 +13,9 @@ class TimerSink : Sink private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -31,9 +31,9 @@ class TimerOneOffSink : Si private let _parent: Parent - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -59,16 +59,16 @@ class Timer: Producer { _period = period } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + override func run(observer: O) -> Disposable { if let _ = _period { - let sink = TimerSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + let sink = TimerSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } else { - let sink = TimerOneOffSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + let sink = TimerOneOffSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/ToArray.swift b/RxSwift/Observables/Implementations/ToArray.swift index c52cf710..1b514d26 100644 --- a/RxSwift/Observables/Implementations/ToArray.swift +++ b/RxSwift/Observables/Implementations/ToArray.swift @@ -14,10 +14,10 @@ class ToArraySink : Sink< let _parent: Parent var _list = Array() - init(parent: Parent, observer: O, cancel: Disposable) { - self._parent = parent + init(parent: Parent, observer: O) { + _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func on(event: Event) { @@ -42,9 +42,9 @@ class ToArray : Producer<[SourceType]> { _source = source } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ToArraySink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribe(sink) + override func run(observer: O) -> Disposable { + let sink = ToArraySink(parent: self, observer: observer) + sink.disposable = _source.subscribe(sink) + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Using.swift b/RxSwift/Observables/Implementations/Using.swift index 6c852634..ed4a891a 100644 --- a/RxSwift/Observables/Implementations/Using.swift +++ b/RxSwift/Observables/Implementations/Using.swift @@ -15,9 +15,9 @@ class UsingSink Disposable { @@ -70,9 +70,9 @@ class Using: Producer { _observableFactory = observableFactory } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = UsingSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = UsingSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/WithLatestFrom.swift b/RxSwift/Observables/Implementations/WithLatestFrom.swift index b2cf3233..685c56d7 100644 --- a/RxSwift/Observables/Implementations/WithLatestFrom.swift +++ b/RxSwift/Observables/Implementations/WithLatestFrom.swift @@ -8,21 +8,24 @@ import Foundation -class WithLatestFromSink : Sink, ObserverType { - +class WithLatestFromSink + : Sink + , ObserverType + , LockOwnerType + , SynchronizedOnType { + typealias Parent = WithLatestFrom typealias E = FirstType private let _parent: Parent - private var _lock = NSRecursiveLock() + var _lock = NSRecursiveLock() private var _latest: SecondType? - - - init(parent: Parent, observer: O, cancel: Disposable) { + + init(parent: Parent, observer: O) { _parent = parent - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func run() -> Disposable { @@ -34,60 +37,70 @@ class WithLatestFromSink) { - _lock.performLocked { - switch event { - case let .Next(value): - guard let latest = _latest else { return } - do { - let res = try _parent._resultSelector(value, latest) - - observer?.onNext(res) - } catch let e { - observer?.onError(e) - dispose() - } - case .Completed: - observer?.onComplete() - dispose() - case let .Error(error): - observer?.onError(error) + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + switch event { + case let .Next(value): + guard let latest = _latest else { return } + do { + let res = try _parent._resultSelector(value, latest) + + observer?.onNext(res) + } catch let e { + observer?.onError(e) dispose() } + case .Completed: + observer?.onComplete() + dispose() + case let .Error(error): + observer?.onError(error) + dispose() } } } -class WithLatestFromSecond: ObserverType { +class WithLatestFromSecond + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias Parent = WithLatestFromSink typealias E = SecondType private let _parent: Parent private let _disposable: Disposable - + + var _lock: NSRecursiveLock { + get { + return _parent._lock + } + } + init(parent: Parent, disposable: Disposable) { _parent = parent _disposable = disposable } func on(event: Event) { + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { switch event { case let .Next(value): - _parent._lock.performLocked { - _parent._latest = value - } + _parent._latest = value case .Completed: _disposable.dispose() case let .Error(error): - _parent._lock.performLocked { - _parent.observer?.onError(error) - _parent.dispose() - } + _parent.observer?.onError(error) + _parent.dispose() } } - } class WithLatestFrom: Producer { @@ -103,10 +116,9 @@ class WithLatestFrom: Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - - let sink = WithLatestFromSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = WithLatestFromSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/Zip+CollectionType.swift b/RxSwift/Observables/Implementations/Zip+CollectionType.swift index a2339599..f2b188a8 100644 --- a/RxSwift/Observables/Implementations/Zip+CollectionType.swift +++ b/RxSwift/Observables/Implementations/Zip+CollectionType.swift @@ -8,7 +8,8 @@ import Foundation -class ZipCollectionTypeSink : Sink { +class ZipCollectionTypeSink + : Sink { typealias Parent = ZipCollectionType typealias SourceElement = C.Generator.Element.E @@ -23,7 +24,7 @@ class ZipCollectionTypeSink](count: parent.count, repeatedValue: Queue(capacity: 4)) _isDone = [Bool](count: parent.count, repeatedValue: false) @@ -34,11 +35,11 @@ class ZipCollectionTypeSink, atIndex: Int) { - _lock.performLocked { + _lock.lock(); defer { _lock.unlock() } // { switch event { case .Next(let element): _values[atIndex].enqueue(element) @@ -97,7 +98,7 @@ class ZipCollectionTypeSink Disposable { @@ -128,9 +129,9 @@ class ZipCollectionType(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipCollectionTypeSink(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipCollectionTypeSink(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } diff --git a/RxSwift/Observables/Implementations/Zip+arity.swift b/RxSwift/Observables/Implementations/Zip+arity.swift index 196cd76c..7d70640a 100644 --- a/RxSwift/Observables/Implementations/Zip+arity.swift +++ b/RxSwift/Observables/Implementations/Zip+arity.swift @@ -39,9 +39,9 @@ class ZipSink2_ : ZipSink { var _values1: Queue = Queue(capacity: 2) var _values2: Queue = Queue(capacity: 2) - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 2, observer: observer, cancel: cancel) + super.init(arity: 2, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -60,8 +60,8 @@ class ZipSink2_ : ZipSink { let subscription1 = SingleAssignmentDisposable() let subscription2 = SingleAssignmentDisposable() - let observer1 = ZipObserver(lock: lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) - let observer2 = ZipObserver(lock: lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) + let observer1 = ZipObserver(lock: _lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) + let observer2 = ZipObserver(lock: _lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) subscription1.disposable = _parent.source1.subscribe(observer1) subscription2.disposable = _parent.source2.subscribe(observer2) @@ -92,10 +92,10 @@ class Zip2 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink2_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink2_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -129,9 +129,9 @@ class ZipSink3_ : ZipSink { var _values2: Queue = Queue(capacity: 2) var _values3: Queue = Queue(capacity: 2) - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 3, observer: observer, cancel: cancel) + super.init(arity: 3, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -152,9 +152,9 @@ class ZipSink3_ : ZipSink { let subscription2 = SingleAssignmentDisposable() let subscription3 = SingleAssignmentDisposable() - let observer1 = ZipObserver(lock: lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) - let observer2 = ZipObserver(lock: lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) - let observer3 = ZipObserver(lock: lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) + let observer1 = ZipObserver(lock: _lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) + let observer2 = ZipObserver(lock: _lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) + let observer3 = ZipObserver(lock: _lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) subscription1.disposable = _parent.source1.subscribe(observer1) subscription2.disposable = _parent.source2.subscribe(observer2) @@ -189,10 +189,10 @@ class Zip3 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink3_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink3_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -227,9 +227,9 @@ class ZipSink4_ : ZipSink { var _values3: Queue = Queue(capacity: 2) var _values4: Queue = Queue(capacity: 2) - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 4, observer: observer, cancel: cancel) + super.init(arity: 4, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -252,10 +252,10 @@ class ZipSink4_ : ZipSink { let subscription3 = SingleAssignmentDisposable() let subscription4 = SingleAssignmentDisposable() - let observer1 = ZipObserver(lock: lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) - let observer2 = ZipObserver(lock: lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) - let observer3 = ZipObserver(lock: lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) - let observer4 = ZipObserver(lock: lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) + let observer1 = ZipObserver(lock: _lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) + let observer2 = ZipObserver(lock: _lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) + let observer3 = ZipObserver(lock: _lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) + let observer4 = ZipObserver(lock: _lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) subscription1.disposable = _parent.source1.subscribe(observer1) subscription2.disposable = _parent.source2.subscribe(observer2) @@ -294,10 +294,10 @@ class Zip4 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink4_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink4_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -333,9 +333,9 @@ class ZipSink5_ : ZipSink { var _values4: Queue = Queue(capacity: 2) var _values5: Queue = Queue(capacity: 2) - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 5, observer: observer, cancel: cancel) + super.init(arity: 5, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -360,11 +360,11 @@ class ZipSink5_ : ZipSink { let subscription4 = SingleAssignmentDisposable() let subscription5 = SingleAssignmentDisposable() - let observer1 = ZipObserver(lock: lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) - let observer2 = ZipObserver(lock: lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) - let observer3 = ZipObserver(lock: lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) - let observer4 = ZipObserver(lock: lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) - let observer5 = ZipObserver(lock: lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) + let observer1 = ZipObserver(lock: _lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) + let observer2 = ZipObserver(lock: _lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) + let observer3 = ZipObserver(lock: _lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) + let observer4 = ZipObserver(lock: _lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) + let observer5 = ZipObserver(lock: _lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) subscription1.disposable = _parent.source1.subscribe(observer1) subscription2.disposable = _parent.source2.subscribe(observer2) @@ -407,10 +407,10 @@ class Zip5 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink5_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink5_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -447,9 +447,9 @@ class ZipSink6_ : ZipSink { var _values5: Queue = Queue(capacity: 2) var _values6: Queue = Queue(capacity: 2) - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 6, observer: observer, cancel: cancel) + super.init(arity: 6, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -476,12 +476,12 @@ class ZipSink6_ : ZipSink { let subscription5 = SingleAssignmentDisposable() let subscription6 = SingleAssignmentDisposable() - let observer1 = ZipObserver(lock: lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) - let observer2 = ZipObserver(lock: lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) - let observer3 = ZipObserver(lock: lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) - let observer4 = ZipObserver(lock: lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) - let observer5 = ZipObserver(lock: lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) - let observer6 = ZipObserver(lock: lock, parent: self, index: 5, setNextValue: { self._values6.enqueue($0) }, this: subscription6) + let observer1 = ZipObserver(lock: _lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) + let observer2 = ZipObserver(lock: _lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) + let observer3 = ZipObserver(lock: _lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) + let observer4 = ZipObserver(lock: _lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) + let observer5 = ZipObserver(lock: _lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) + let observer6 = ZipObserver(lock: _lock, parent: self, index: 5, setNextValue: { self._values6.enqueue($0) }, this: subscription6) subscription1.disposable = _parent.source1.subscribe(observer1) subscription2.disposable = _parent.source2.subscribe(observer2) @@ -528,10 +528,10 @@ class Zip6 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink6_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink6_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -569,9 +569,9 @@ class ZipSink7_ : ZipSink { var _values6: Queue = Queue(capacity: 2) var _values7: Queue = Queue(capacity: 2) - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 7, observer: observer, cancel: cancel) + super.init(arity: 7, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -600,13 +600,13 @@ class ZipSink7_ : ZipSink { let subscription6 = SingleAssignmentDisposable() let subscription7 = SingleAssignmentDisposable() - let observer1 = ZipObserver(lock: lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) - let observer2 = ZipObserver(lock: lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) - let observer3 = ZipObserver(lock: lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) - let observer4 = ZipObserver(lock: lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) - let observer5 = ZipObserver(lock: lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) - let observer6 = ZipObserver(lock: lock, parent: self, index: 5, setNextValue: { self._values6.enqueue($0) }, this: subscription6) - let observer7 = ZipObserver(lock: lock, parent: self, index: 6, setNextValue: { self._values7.enqueue($0) }, this: subscription7) + let observer1 = ZipObserver(lock: _lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) + let observer2 = ZipObserver(lock: _lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) + let observer3 = ZipObserver(lock: _lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) + let observer4 = ZipObserver(lock: _lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) + let observer5 = ZipObserver(lock: _lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) + let observer6 = ZipObserver(lock: _lock, parent: self, index: 5, setNextValue: { self._values6.enqueue($0) }, this: subscription6) + let observer7 = ZipObserver(lock: _lock, parent: self, index: 6, setNextValue: { self._values7.enqueue($0) }, this: subscription7) subscription1.disposable = _parent.source1.subscribe(observer1) subscription2.disposable = _parent.source2.subscribe(observer2) @@ -657,10 +657,10 @@ class Zip7 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink7_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink7_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } @@ -699,9 +699,9 @@ class ZipSink8_ : ZipSink { var _values7: Queue = Queue(capacity: 2) var _values8: Queue = Queue(capacity: 2) - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: 8, observer: observer, cancel: cancel) + super.init(arity: 8, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -732,14 +732,14 @@ class ZipSink8_ : ZipSink { let subscription7 = SingleAssignmentDisposable() let subscription8 = SingleAssignmentDisposable() - let observer1 = ZipObserver(lock: lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) - let observer2 = ZipObserver(lock: lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) - let observer3 = ZipObserver(lock: lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) - let observer4 = ZipObserver(lock: lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) - let observer5 = ZipObserver(lock: lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) - let observer6 = ZipObserver(lock: lock, parent: self, index: 5, setNextValue: { self._values6.enqueue($0) }, this: subscription6) - let observer7 = ZipObserver(lock: lock, parent: self, index: 6, setNextValue: { self._values7.enqueue($0) }, this: subscription7) - let observer8 = ZipObserver(lock: lock, parent: self, index: 7, setNextValue: { self._values8.enqueue($0) }, this: subscription8) + let observer1 = ZipObserver(lock: _lock, parent: self, index: 0, setNextValue: { self._values1.enqueue($0) }, this: subscription1) + let observer2 = ZipObserver(lock: _lock, parent: self, index: 1, setNextValue: { self._values2.enqueue($0) }, this: subscription2) + let observer3 = ZipObserver(lock: _lock, parent: self, index: 2, setNextValue: { self._values3.enqueue($0) }, this: subscription3) + let observer4 = ZipObserver(lock: _lock, parent: self, index: 3, setNextValue: { self._values4.enqueue($0) }, this: subscription4) + let observer5 = ZipObserver(lock: _lock, parent: self, index: 4, setNextValue: { self._values5.enqueue($0) }, this: subscription5) + let observer6 = ZipObserver(lock: _lock, parent: self, index: 5, setNextValue: { self._values6.enqueue($0) }, this: subscription6) + let observer7 = ZipObserver(lock: _lock, parent: self, index: 6, setNextValue: { self._values7.enqueue($0) }, this: subscription7) + let observer8 = ZipObserver(lock: _lock, parent: self, index: 7, setNextValue: { self._values8.enqueue($0) }, this: subscription8) subscription1.disposable = _parent.source1.subscribe(observer1) subscription2.disposable = _parent.source2.subscribe(observer2) @@ -794,10 +794,10 @@ class Zip8 : Producer { _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink8_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink8_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } diff --git a/RxSwift/Observables/Implementations/Zip+arity.tt b/RxSwift/Observables/Implementations/Zip+arity.tt index 6b9a0460..c16b8418 100644 --- a/RxSwift/Observables/Implementations/Zip+arity.tt +++ b/RxSwift/Observables/Implementations/Zip+arity.tt @@ -38,9 +38,9 @@ class ZipSink<%= i %>_<<%= (Array(1...i).map { "E\($0)" }).joinWithSeparator(", " var _values\($0): Queue = Queue(capacity: 2)" }).joinWithSeparator("\n") %> - init(parent: Parent, observer: O, cancel: Disposable) { + init(parent: Parent, observer: O) { _parent = parent - super.init(arity: <%= i %>, observer: observer, cancel: cancel) + super.init(arity: <%= i %>, observer: observer) } override func hasElements(index: Int) -> Bool { @@ -61,7 +61,7 @@ class ZipSink<%= i %>_<<%= (Array(1...i).map { "E\($0)" }).joinWithSeparator(", }).joinWithSeparator("\n") %> <%= (Array(1...i).map { -" let observer\($0) = ZipObserver(lock: lock, parent: self, index: \($0 - 1), setNextValue: { self._values\($0).enqueue($0) }, this: subscription\($0))" +" let observer\($0) = ZipObserver(lock: _lock, parent: self, index: \($0 - 1), setNextValue: { self._values\($0).enqueue($0) }, this: subscription\($0))" }).joinWithSeparator("\n") %> <%= (Array(1...i).map { @@ -93,10 +93,10 @@ class Zip<%= i %><<%= (Array(1...i).map { "E\($0)" }).joinWithSeparator(", ") %> _resultSelector = resultSelector } - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = ZipSink<%= i %>_(parent: self, observer: observer, cancel: cancel) - setSink(sink) - return sink.run() + override func run(observer: O) -> Disposable { + let sink = ZipSink<%= i %>_(parent: self, observer: observer) + sink.disposable = sink.run() + return sink } } diff --git a/RxSwift/Observables/Implementations/Zip.swift b/RxSwift/Observables/Implementations/Zip.swift index 71927516..273f80ff 100644 --- a/RxSwift/Observables/Implementations/Zip.swift +++ b/RxSwift/Observables/Implementations/Zip.swift @@ -18,18 +18,18 @@ protocol ZipSinkProtocol : class class ZipSink : Sink, ZipSinkProtocol { typealias Element = O.E - let arity: Int - - let lock = NSRecursiveLock() - + let _arity: Int + + let _lock = NSRecursiveLock() + // state private var _isDone: [Bool] - init(arity: Int, observer: O, cancel: Disposable) { + init(arity: Int, observer: O) { _isDone = [Bool](count: arity, repeatedValue: false) - self.arity = arity + _arity = arity - super.init(observer: observer, cancel: cancel) + super.init(observer: observer) } func getResult() throws -> Element { @@ -43,7 +43,7 @@ class ZipSink : Sink, ZipSinkProtocol { func next(index: Int) { var hasValueAll = true - for i in 0 ..< arity { + for i in 0 ..< _arity { if !hasElements(i) { hasValueAll = false; break; @@ -102,13 +102,16 @@ class ZipSink : Sink, ZipSinkProtocol { } } -class ZipObserver : ObserverType { +class ZipObserver + : ObserverType + , LockOwnerType + , SynchronizedOnType { typealias E = ElementType typealias ValueSetter = (ElementType) -> () private var _parent: ZipSinkProtocol? - private let _lock: NSRecursiveLock + let _lock: NSRecursiveLock // state private let _index: Int @@ -124,7 +127,10 @@ class ZipObserver : ObserverType { } func on(event: Event) { - + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { if let _ = _parent { switch event { case .Next(_): @@ -136,17 +142,15 @@ class ZipObserver : ObserverType { } } - _lock.performLocked { - if let parent = _parent { - switch event { - case .Next(let value): - _setNextValue(value) - parent.next(_index) - case .Error(let error): - parent.fail(error) - case .Completed: - parent.done(_index) - } + if let parent = _parent { + switch event { + case .Next(let value): + _setNextValue(value) + parent.next(_index) + case .Error(let error): + parent.fail(error) + case .Completed: + parent.done(_index) } } } diff --git a/RxSwift/Observers/TailRecursiveSink.swift b/RxSwift/Observers/TailRecursiveSink.swift index 93bee506..c4021064 100644 --- a/RxSwift/Observers/TailRecursiveSink.swift +++ b/RxSwift/Observers/TailRecursiveSink.swift @@ -19,8 +19,8 @@ class TailRecursiveSink Disposable { diff --git a/RxSwift/Schedulers/CurrentThreadScheduler.swift b/RxSwift/Schedulers/CurrentThreadScheduler.swift index b839a4a8..ada3b894 100644 --- a/RxSwift/Schedulers/CurrentThreadScheduler.swift +++ b/RxSwift/Schedulers/CurrentThreadScheduler.swift @@ -104,7 +104,7 @@ public class CurrentThreadScheduler : ImmediateSchedulerType { if CurrentThreadScheduler.isScheduleRequired { CurrentThreadScheduler.isScheduleRequired = false - action(state) + let disposable = action(state) defer { CurrentThreadScheduler.isScheduleRequired = true @@ -112,7 +112,7 @@ public class CurrentThreadScheduler : ImmediateSchedulerType { } guard let queue = CurrentThreadScheduler.queue else { - return NopDisposable.instance + return disposable } while let latest = queue.value.tryDequeue() { @@ -122,7 +122,7 @@ public class CurrentThreadScheduler : ImmediateSchedulerType { latest.invoke() } - return NopDisposable.instance + return disposable } let existingQueue = CurrentThreadScheduler.queue diff --git a/RxTests/PerformanceTests/main.swift b/RxTests/PerformanceTests/main.swift index 289abde2..414168da 100644 --- a/RxTests/PerformanceTests/main.swift +++ b/RxTests/PerformanceTests/main.swift @@ -25,17 +25,17 @@ compareTwoImplementations(benchmarkTime: true, first: { //combineLatest(a, publishSubject - //.shareReplay(1) + .shareReplay(1) + .map { $0 } + .filter { _ in true }// ){ x, _ in x } //.map { $0 } - //.filter { _ in true }// ){ x, _ in x } - //.map { $0 } - .flatMap { just($0) } + //.flatMap { just($0) } .subscribeNext { _ in } - for i in 0..<100 { + for i in 0..<1000 { publishSubject.on(.Next(i)) } diff --git a/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift b/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift index 3440ee91..0d77a9e6 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift @@ -3057,12 +3057,16 @@ extension ObservableStandardSequenceOperatorsTest { func testTakeLast_DecrementCountsFirst() { let k = BehaviorSubject(value: false) - + + var elements = [Bool]() _ = k.takeLast(1).subscribeNext { n in + elements.append(n) k.on(.Next(!n)) } k.on(.Completed) + + XCTAssertEqual(elements, [false]) } } diff --git a/RxTests/RxTest.swift b/RxTests/RxTest.swift index 2f661520..a15f9629 100644 --- a/RxTests/RxTest.swift +++ b/RxTests/RxTest.swift @@ -107,7 +107,7 @@ class RxTest: XCTestCase { #if TRACE_RESOURCES // give 5 sec to clean up resources - for var i = 0; i < 100; ++i { + for var i = 0; i < 10; ++i { if self.startResourceCount < resourceCount { // main schedulers need to finish work NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: 0.05)) diff --git a/RxTests/RxTests.xcodeproj/xcshareddata/xcschemes/RxTests-OSX.xcscheme b/RxTests/RxTests.xcodeproj/xcshareddata/xcschemes/RxTests-OSX.xcscheme index 4f6e4922..a9d93f0f 100644 --- a/RxTests/RxTests.xcodeproj/xcshareddata/xcschemes/RxTests-OSX.xcscheme +++ b/RxTests/RxTests.xcodeproj/xcshareddata/xcschemes/RxTests-OSX.xcscheme @@ -52,7 +52,7 @@ Date: Sun, 1 Nov 2015 12:21:14 +0100 Subject: [PATCH 12/19] Removes optimizations on `PerformanceTests` because it generates wrong assembly, kudos Swift compiler team. --- RxTests/PerformanceTests/main.swift | 2 +- RxTests/RxTests.xcodeproj/project.pbxproj | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/RxTests/PerformanceTests/main.swift b/RxTests/PerformanceTests/main.swift index 414168da..1d80a525 100644 --- a/RxTests/PerformanceTests/main.swift +++ b/RxTests/PerformanceTests/main.swift @@ -35,7 +35,7 @@ compareTwoImplementations(benchmarkTime: true, first: { } - for i in 0..<1000 { + for i in 0..<100 { publishSubject.on(.Next(i)) } diff --git a/RxTests/RxTests.xcodeproj/project.pbxproj b/RxTests/RxTests.xcodeproj/project.pbxproj index 5b5313c8..1224c280 100644 --- a/RxTests/RxTests.xcodeproj/project.pbxproj +++ b/RxTests/RxTests.xcodeproj/project.pbxproj @@ -1075,6 +1075,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "Krunoslav-Zaher.PerformanceTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Release; }; @@ -1119,6 +1120,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "Krunoslav-Zaher.PerformanceTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = "Release-Tests"; }; From d4cd9cf69b9ef13a75a89804e7515a9fa0fab093 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 1 Nov 2015 12:47:06 +0100 Subject: [PATCH 13/19] Refactors `ReplaySubject` and `BehaviorSubject` to be consistent with `ReplaySubject`. --- RxSwift/Subjects/BehaviorSubject.swift | 111 ++++++++-------- RxSwift/Subjects/ReplaySubject.swift | 170 +++++++++++-------------- 2 files changed, 128 insertions(+), 153 deletions(-) diff --git a/RxSwift/Subjects/BehaviorSubject.swift b/RxSwift/Subjects/BehaviorSubject.swift index 7623332d..4059ce87 100644 --- a/RxSwift/Subjects/BehaviorSubject.swift +++ b/RxSwift/Subjects/BehaviorSubject.swift @@ -8,37 +8,24 @@ import Foundation -private class BehaviorSubjectSubscription : Disposable { - typealias Parent = BehaviorSubject - typealias DisposeKey = Bag>.KeyType - - private let _parent: Parent - private var _disposeKey: DisposeKey? - - init(parent: BehaviorSubject, disposeKey: DisposeKey) { - _parent = parent - _disposeKey = disposeKey - } - - func dispose() { - _parent._lock.performLocked { - if let disposeKey = _disposeKey { - _parent._observers.removeKey(disposeKey) - _disposeKey = nil - } - } - } -} - /** Represents a value that changes over time. Observers can subscribe to the subject to receive the last (or initial) value and all subsequent notifications. */ -public final class BehaviorSubject : Observable, SubjectType, ObserverType, Disposable { +public final class BehaviorSubject + : Observable + , SubjectType + , ObserverType + , LockOwnerType + , SynchronizedOnType + , SynchronizedSubscribeType + , SynchronizedUnsubscribeType + , Disposable { public typealias SubjectObserverType = BehaviorSubject + typealias DisposeKey = Bag>.KeyType - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _disposed = false @@ -50,9 +37,7 @@ public final class BehaviorSubject : Observable, SubjectType, Indicates whether the subject has been disposed. */ public var disposed: Bool { - return _lock.calculateLocked { - return _disposed - } + return _disposed } /** @@ -70,7 +55,7 @@ public final class BehaviorSubject : Observable, SubjectType, - returns: Latest value. */ public func value() throws -> Element { - return try _lock.calculateLockedOrFail { + _lock.lock(); defer { _lock.unlock() } // { if _disposed { throw RxError.DisposedError } @@ -82,7 +67,7 @@ public final class BehaviorSubject : Observable, SubjectType, else { return _value } - } + //} } /** @@ -91,20 +76,22 @@ public final class BehaviorSubject : Observable, SubjectType, - parameter event: Event to send to the observers. */ public func on(event: Event) { - _lock.performLocked { - if _stoppedEvent != nil || _disposed { - return - } - - switch event { - case .Next(let value): - _value = value - case .Error, .Completed: - _stoppedEvent = event - } - - _observers.on(event) + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + if _stoppedEvent != nil || _disposed { + return } + + switch event { + case .Next(let value): + _value = value + case .Error, .Completed: + _stoppedEvent = event + } + + _observers.on(event) } /** @@ -114,22 +101,32 @@ public final class BehaviorSubject : Observable, SubjectType, - returns: Disposable object that can be used to unsubscribe the observer from the subject. */ public override func subscribe(observer: O) -> Disposable { - return _lock.calculateLocked { - if _disposed { - observer.on(.Error(RxError.DisposedError)) - return NopDisposable.instance - } - - if let stoppedEvent = _stoppedEvent { - observer.on(stoppedEvent) - return NopDisposable.instance - } - - let key = _observers.insert(observer.asObserver()) - observer.on(.Next(_value)) - - return BehaviorSubjectSubscription(parent: self, disposeKey: key) + return synchronizedSubscribe(observer) + } + + func _synchronized_subscribe(observer: O) -> Disposable { + if _disposed { + observer.on(.Error(RxError.DisposedError)) + return NopDisposable.instance } + + if let stoppedEvent = _stoppedEvent { + observer.on(stoppedEvent) + return NopDisposable.instance + } + + let key = _observers.insert(observer.asObserver()) + observer.on(.Next(_value)) + + return SubscriptionDisposable(owner: self, key: key) + } + + func _synchronized_unsubscribe(disposeKey: DisposeKey) { + if _disposed { + return + } + + _ = _observers.removeKey(disposeKey) } /** diff --git a/RxSwift/Subjects/ReplaySubject.swift b/RxSwift/Subjects/ReplaySubject.swift index 97332e4c..3ad58d4f 100644 --- a/RxSwift/Subjects/ReplaySubject.swift +++ b/RxSwift/Subjects/ReplaySubject.swift @@ -13,7 +13,11 @@ Represents an object that is both an observable sequence as well as an observer. Each notification is broadcasted to all subscribed and future observers, subject to buffer trimming policies. */ -public class ReplaySubject : Observable, SubjectType, ObserverType, Disposable { +public class ReplaySubject + : Observable + , SubjectType + , ObserverType + , Disposable { public typealias SubjectObserverType = ReplaySubject typealias DisposeKey = Bag>.KeyType @@ -60,9 +64,15 @@ public class ReplaySubject : Observable, SubjectType, Observer } } -class ReplayBufferBase : ReplaySubject { +class ReplayBufferBase + : ReplaySubject + , LockOwnerType + , SynchronizedOnType + , SynchronizedSubscribeType + , SynchronizedUnsubscribeType + , SynchronizedDisposeType { - private let _lock = NSRecursiveLock() + let _lock = NSRecursiveLock() // state private var _disposed = false @@ -86,73 +96,72 @@ class ReplayBufferBase : ReplaySubject { } override func on(event: Event) { - _lock.performLocked { - if _disposed { - return - } - - if _stoppedEvent != nil { - return - } - - switch event { - case .Next(let value): - addValueToBuffer(value) - trim() - _observers.on(event) - case .Error, .Completed: - _stoppedEvent = event - trim() - _observers.on(event) - _observers.removeAll() - } - + synchronizedOn(event) + } + + func _synchronized_on(event: Event) { + if _disposed { + return + } + + if _stoppedEvent != nil { + return + } + + switch event { + case .Next(let value): + addValueToBuffer(value) + trim() + _observers.on(event) + case .Error, .Completed: + _stoppedEvent = event + trim() + _observers.on(event) + _observers.removeAll() } } override func subscribe(observer: O) -> Disposable { - return _lock.calculateLocked { - if _disposed { - observer.on(.Error(RxError.DisposedError)) - return NopDisposable.instance - } - - let AnyObserver = observer.asObserver() - - replayBuffer(AnyObserver) - if let stoppedEvent = _stoppedEvent { - observer.on(stoppedEvent) - return NopDisposable.instance - } - else { - let key = _observers.insert(AnyObserver) - return ReplaySubscription(subject: self, disposeKey: key) - } - } + return synchronizedSubscribe(observer) } - - override func unsubscribe(key: DisposeKey) { - _lock.performLocked { - if _disposed { - return - } - - _ = _observers.removeKey(key) + + func _synchronized_subscribe(observer: O) -> Disposable { + if _disposed { + observer.on(.Error(RxError.DisposedError)) + return NopDisposable.instance + } + + let AnyObserver = observer.asObserver() + + replayBuffer(AnyObserver) + if let stoppedEvent = _stoppedEvent { + observer.on(stoppedEvent) + return NopDisposable.instance + } + else { + let key = _observers.insert(AnyObserver) + return SubscriptionDisposable(owner: self, key: key) } } - func lockedDispose() { - _disposed = true - _stoppedEvent = nil - _observers.removeAll() + func _synchronized_unsubscribe(disposeKey: DisposeKey) { + if _disposed { + return + } + + _ = _observers.removeKey(disposeKey) } override func dispose() { super.dispose() - - _lock.performLocked { - lockedDispose() - } + + synchronizedDispose() + } + + func _synchronized_dispose() { + _disposed = true + _stoppedEvent = nil + _observers.removeAll() } } @@ -176,10 +185,9 @@ class ReplayOne : ReplayBufferBase { observer.on(.Next(value)) } } - - override func lockedDispose() { - super.lockedDispose() - + + override func _synchronized_dispose() { + super._synchronized_dispose() _value = nil } } @@ -200,9 +208,9 @@ class ReplayManyBase : ReplayBufferBase { observer.on(.Next(item)) } } - - override func lockedDispose() { - super.lockedDispose() + + override func _synchronized_dispose() { + super._synchronized_dispose() _queue = Queue(capacity: 0) } } @@ -231,34 +239,4 @@ class ReplayAll : ReplayManyBase { override func trim() { } -} - -class ReplaySubscription : Disposable { - typealias Subject = ReplaySubject - typealias DisposeKey = ReplayBufferBase.DisposeKey - - private var _lock = SpinLock() - - // state - private var _subject: Subject? - private var _disposeKey: DisposeKey? - - init(subject: Subject, disposeKey: DisposeKey) { - _subject = subject - _disposeKey = disposeKey - } - - func dispose() { - let oldState = _lock.calculateLocked { () -> (Subject?, DisposeKey?) in - let state = (self._subject, self._disposeKey) - self._subject = nil - self._disposeKey = nil - - return state - } - - if let subject = oldState.0, let disposeKey = oldState.1 { - subject.unsubscribe(disposeKey) - } - } -} +} \ No newline at end of file From 99a75f586e4664810602dbe82ced05c4a5f1c63f Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 1 Nov 2015 20:56:34 +0100 Subject: [PATCH 14/19] Remove `AsObservable` implementation. --- .../Implementations/AsObservable.swift | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 RxSwift/Observables/Implementations/AsObservable.swift diff --git a/RxSwift/Observables/Implementations/AsObservable.swift b/RxSwift/Observables/Implementations/AsObservable.swift deleted file mode 100644 index 134a252c..00000000 --- a/RxSwift/Observables/Implementations/AsObservable.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// AsObservable.swift -// Rx -// -// Created by Krunoslav Zaher on 2/27/15. -// Copyright (c) 2015 Krunoslav Zaher. All rights reserved. -// - -import Foundation - -class AsObservableSink : Sink, ObserverType { - typealias Element = O.E - - override init(observer: O, cancel: Disposable) { - super.init(observer: observer, cancel: cancel) - } - - func on(event: Event) { - observer?.on(event) - - switch event { - case .Error, .Completed: - dispose() - default: break - } - } -} - -class AsObservable : Producer { - - private let _source: Observable - - init(source: Observable) { - _source = source - } - - override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - let sink = AsObservableSink(observer: observer, cancel: cancel) - setSink(sink) - return _source.subscribeSafe(sink) - } -} From 71ee2eeb347ee6144ca5f32c11f0c165ed6acd84 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 1 Nov 2015 21:42:25 +0100 Subject: [PATCH 15/19] Extends `ObservableType` instead of `ObservableConvertibleType`. --- RxSwift/Observables/Observable+Aggregate.swift | 2 +- RxSwift/Observables/Observable+Binding.swift | 10 +++++----- .../Observables/Observable+Concurrency.swift | 2 +- RxSwift/Observables/Observable+Debug.swift | 2 +- RxSwift/Observables/Observable+Multiple.swift | 18 +++++++++--------- RxSwift/Observables/Observable+Single.swift | 12 ++++++------ .../Observable+StandardSequenceOperators.swift | 18 +++++++++--------- RxSwift/Observables/Observable+Time.swift | 12 ++++++------ 8 files changed, 38 insertions(+), 38 deletions(-) diff --git a/RxSwift/Observables/Observable+Aggregate.swift b/RxSwift/Observables/Observable+Aggregate.swift index c2a93053..4f14ad5a 100644 --- a/RxSwift/Observables/Observable+Aggregate.swift +++ b/RxSwift/Observables/Observable+Aggregate.swift @@ -10,7 +10,7 @@ import Foundation // MARK: reduce -extension ObservableConvertibleType { +extension ObservableType { /** Applies an `accumulator` function over an observable sequence, returning the result of the aggregation as a single element in the result sequence. The specified `seed` value is used as the initial accumulator value. diff --git a/RxSwift/Observables/Observable+Binding.swift b/RxSwift/Observables/Observable+Binding.swift index 9ccad52e..c0912cd2 100644 --- a/RxSwift/Observables/Observable+Binding.swift +++ b/RxSwift/Observables/Observable+Binding.swift @@ -10,7 +10,7 @@ import Foundation // MARK: multicast -extension ObservableConvertibleType { +extension ObservableType { /** Multicasts the source sequence notifications through the specified subject to the resulting connectable observable. @@ -52,7 +52,7 @@ extension ObservableConvertibleType { // MARK: publish -extension ObservableConvertibleType { +extension ObservableType { /** Returns a connectable observable sequence that shares a single subscription to the underlying sequence. @@ -69,7 +69,7 @@ extension ObservableConvertibleType { // MARK: replay -extension ObservableConvertibleType { +extension ObservableType { /** Returns a connectable observable sequence that shares a single subscription to the underlying sequence replaying bufferSize elements. @@ -103,7 +103,7 @@ extension ConnectableObservableType { // MARK: share -extension ObservableConvertibleType { +extension ObservableType { /** Returns an observable sequence that shares a single subscription to the underlying sequence. @@ -120,7 +120,7 @@ extension ObservableConvertibleType { // MARK: shareReplay -extension ObservableConvertibleType { +extension ObservableType { /** Returns an observable sequence that shares a single subscription to the underlying sequence replaying notifications subject to a maximum time length for the replay buffer. diff --git a/RxSwift/Observables/Observable+Concurrency.swift b/RxSwift/Observables/Observable+Concurrency.swift index 1f5de591..2bf4de71 100644 --- a/RxSwift/Observables/Observable+Concurrency.swift +++ b/RxSwift/Observables/Observable+Concurrency.swift @@ -10,7 +10,7 @@ import Foundation // MARK: observeOn -extension ObservableConvertibleType { +extension ObservableType { /** Wraps the source sequence in order to run its observer callbacks on the specified scheduler. diff --git a/RxSwift/Observables/Observable+Debug.swift b/RxSwift/Observables/Observable+Debug.swift index 4090c993..41df23f8 100644 --- a/RxSwift/Observables/Observable+Debug.swift +++ b/RxSwift/Observables/Observable+Debug.swift @@ -10,7 +10,7 @@ import Foundation // MARK: debug -extension ObservableConvertibleType { +extension ObservableType { /** Prints received events for all observers on standard output. diff --git a/RxSwift/Observables/Observable+Multiple.swift b/RxSwift/Observables/Observable+Multiple.swift index bba42c2a..d6b4dd6c 100644 --- a/RxSwift/Observables/Observable+Multiple.swift +++ b/RxSwift/Observables/Observable+Multiple.swift @@ -42,7 +42,7 @@ extension CollectionType where Generator.Element : ObservableConvertibleType { // MARK: switch -extension ObservableConvertibleType where E : ObservableConvertibleType { +extension ObservableType where E : ObservableConvertibleType { /** Transforms an observable sequence of observable sequences into an observable sequence @@ -61,7 +61,7 @@ extension ObservableConvertibleType where E : ObservableConvertibleType { // MARK: concat -extension ObservableConvertibleType { +extension ObservableType { /** Concatenates the second observable sequence to `self` upon successful termination of `self`. @@ -89,7 +89,7 @@ extension SequenceType where Generator.Element : ObservableConvertibleType { } } -extension ObservableConvertibleType where E : ObservableConvertibleType { +extension ObservableType where E : ObservableConvertibleType { /** Concatenates all inner observable sequences, as long as the previous observable sequence terminated successfully. @@ -104,7 +104,7 @@ extension ObservableConvertibleType where E : ObservableConvertibleType { // MARK: merge -extension ObservableConvertibleType where E : ObservableConvertibleType { +extension ObservableType where E : ObservableConvertibleType { /** Merges elements from all observable sequences in the given enumerable sequence into a single observable sequence. @@ -131,7 +131,7 @@ extension ObservableConvertibleType where E : ObservableConvertibleType { // MARK: catch -extension ObservableConvertibleType { +extension ObservableType { /** Continues an observable sequence that is terminated by an error with the observable sequence produced by the handler. @@ -174,7 +174,7 @@ extension SequenceType where Generator.Element : ObservableConvertibleType { // MARK: takeUntil -extension ObservableConvertibleType { +extension ObservableType { /** Returns the elements from the source observable sequence until the other observable sequence produces an element. @@ -191,7 +191,7 @@ extension ObservableConvertibleType { // MARK: skipUntil -extension ObservableConvertibleType { +extension ObservableType { /** Returns the elements from the source observable sequence until the other observable sequence produces an element. @@ -208,7 +208,7 @@ extension ObservableConvertibleType { // MARK: amb -extension ObservableConvertibleType { +extension ObservableType { /** Propagates the observable sequence that reacts first. @@ -242,7 +242,7 @@ extension SequenceType where Generator.Element : ObservableConvertibleType { // withLatestFrom -extension ObservableConvertibleType { +extension ObservableType { /** Merges two observable sequences into one observable sequence by combining each element from self with the latest element from the second source, if any. diff --git a/RxSwift/Observables/Observable+Single.swift b/RxSwift/Observables/Observable+Single.swift index b1434a2b..4cf01d78 100644 --- a/RxSwift/Observables/Observable+Single.swift +++ b/RxSwift/Observables/Observable+Single.swift @@ -10,7 +10,7 @@ import Foundation // MARK: distinct until changed -extension ObservableConvertibleType where E: Equatable { +extension ObservableType where E: Equatable { /** Returns an observable sequence that contains only distinct contiguous elements according to equality operator. @@ -24,7 +24,7 @@ extension ObservableConvertibleType where E: Equatable { } } -extension ObservableConvertibleType { +extension ObservableType { /** Returns an observable sequence that contains only distinct contiguous elements according to the `keySelector`. @@ -65,7 +65,7 @@ extension ObservableConvertibleType { // MARK: do -extension ObservableConvertibleType { +extension ObservableType { /** Invokes an action for each event in the observable sequence, and propagates all observer messages through the result sequence. @@ -105,7 +105,7 @@ extension ObservableConvertibleType { // MARK: startWith -extension ObservableConvertibleType { +extension ObservableType { /** Prepends a sequence of values to an observable sequence. @@ -122,7 +122,7 @@ extension ObservableConvertibleType { // MARK: retry -extension ObservableConvertibleType { +extension ObservableType { /** Repeats the source observable sequence until it successfully terminates. @@ -153,7 +153,7 @@ extension ObservableConvertibleType { // MARK: scan -extension ObservableConvertibleType { +extension ObservableType { /** Applies an accumulator function over an observable sequence and returns each intermediate result. The specified seed value is used as the initial accumulator value. diff --git a/RxSwift/Observables/Observable+StandardSequenceOperators.swift b/RxSwift/Observables/Observable+StandardSequenceOperators.swift index 6ff01147..5278c3de 100644 --- a/RxSwift/Observables/Observable+StandardSequenceOperators.swift +++ b/RxSwift/Observables/Observable+StandardSequenceOperators.swift @@ -10,7 +10,7 @@ import Foundation // MARK: filter aka where -extension ObservableConvertibleType { +extension ObservableType { /** Filters the elements of an observable sequence based on a predicate. @@ -27,7 +27,7 @@ extension ObservableConvertibleType { // MARK: takeWhile -extension ObservableConvertibleType { +extension ObservableType { /** Returns elements from an observable sequence as long as a specified condition is true. @@ -58,7 +58,7 @@ extension ObservableConvertibleType { // MARK: take -extension ObservableConvertibleType { +extension ObservableType { /** Returns a specified number of contiguous elements from the start of an observable sequence. @@ -80,7 +80,7 @@ extension ObservableConvertibleType { // MARK: takeLast -extension ObservableConvertibleType { +extension ObservableType { /** Returns a specified number of contiguous elements from the end of an observable sequence. @@ -100,7 +100,7 @@ extension ObservableConvertibleType { // MARK: skip -extension ObservableConvertibleType { +extension ObservableType { /** Bypasses a specified number of elements in an observable sequence and then returns the remaining elements. @@ -117,7 +117,7 @@ extension ObservableConvertibleType { // MARK: SkipWhile -extension ObservableConvertibleType { +extension ObservableType { /** Bypasses elements in an observable sequence as long as a specified condition is true and then returns the remaining elements. @@ -145,7 +145,7 @@ extension ObservableConvertibleType { // MARK: map aka select -extension ObservableConvertibleType { +extension ObservableType { /** Projects each element of an observable sequence into a new form. @@ -174,7 +174,7 @@ extension ObservableConvertibleType { // MARK: flatMap -extension ObservableConvertibleType { +extension ObservableType { /** Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences into one observable sequence. @@ -203,7 +203,7 @@ extension ObservableConvertibleType { // elementAt -extension ObservableConvertibleType { +extension ObservableType { /** Returns a sequence emitting only item _n_ emitted by an Observable diff --git a/RxSwift/Observables/Observable+Time.swift b/RxSwift/Observables/Observable+Time.swift index 262df3bf..6917b79a 100644 --- a/RxSwift/Observables/Observable+Time.swift +++ b/RxSwift/Observables/Observable+Time.swift @@ -9,7 +9,7 @@ import Foundation // MARK: throttle -extension ObservableConvertibleType { +extension ObservableType { /** Ignores elements from an observable sequence which are followed by another element within a specified relative time duration, using the specified scheduler to run throttling timers. @@ -44,7 +44,7 @@ extension ObservableConvertibleType { // MARK: sample -extension ObservableConvertibleType { +extension ObservableType { /** Samples the source observable sequence using a samper observable sequence producing sampling ticks. @@ -136,7 +136,7 @@ public func timer(dueTime: S.TimeInterval, _ scheduler: S) // MARK: take -extension ObservableConvertibleType { +extension ObservableType { /** Takes elements for the specified duration from the start of the observable source sequence, using the specified scheduler to run timers. @@ -154,7 +154,7 @@ extension ObservableConvertibleType { // MARK: skip -extension ObservableConvertibleType { +extension ObservableType { /** Skips elements for the specified duration from the start of the observable source sequence, using the specified scheduler to run timers. @@ -173,7 +173,7 @@ extension ObservableConvertibleType { // MARK: delaySubscription -extension ObservableConvertibleType { +extension ObservableType { /** Time shifts the observable sequence by delaying the subscription with the specified relative time duration, using the specified scheduler to run timers. @@ -191,7 +191,7 @@ extension ObservableConvertibleType { // MARK: buffer -extension ObservableConvertibleType { +extension ObservableType { /** Projects each element of an observable sequence into a buffer that's sent out when either it's full or a given amount of time has elapsed, using the specified scheduler to run timers. From dcfe2c5f0cdcf86543584027053a8e3796be5095 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 1 Nov 2015 21:58:57 +0100 Subject: [PATCH 16/19] Optimizations for `observeOn`. --- RxSwift/Disposables/ScheduledDisposable.swift | 10 +++++--- .../Implementations/ObserveOn.swift | 1 + .../ObserveOnSerialDispatchQueue.swift | 25 +++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/RxSwift/Disposables/ScheduledDisposable.swift b/RxSwift/Disposables/ScheduledDisposable.swift index 8ad765e3..dea13edf 100644 --- a/RxSwift/Disposables/ScheduledDisposable.swift +++ b/RxSwift/Disposables/ScheduledDisposable.swift @@ -8,6 +8,11 @@ import Foundation +private let disposeScheduledDisposable: ScheduledDisposable -> Disposable = { sd in + sd.disposeInner() + return NopDisposable.instance +} + /** Represents a disposable resource whose disposal invocation will be scheduled on the specified scheduler. */ @@ -43,10 +48,7 @@ public class ScheduledDisposable : Cancelable { Disposes the wrapped disposable on the provided scheduler. */ public func dispose() { - scheduler.schedule(()) { - self.disposeInner() - return NopDisposable.instance - } + scheduler.schedule(self, action: disposeScheduledDisposable) } func disposeInner() { diff --git a/RxSwift/Observables/Implementations/ObserveOn.swift b/RxSwift/Observables/Implementations/ObserveOn.swift index 5eb1298d..074dded5 100644 --- a/RxSwift/Observables/Implementations/ObserveOn.swift +++ b/RxSwift/Observables/Implementations/ObserveOn.swift @@ -127,6 +127,7 @@ class ObserveOnSink : ObserverBase { _lock.lock(); defer { _lock.unlock() } // { _observer = nil + // } } } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift b/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift index 7d3f5675..4a6a4328 100644 --- a/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift +++ b/RxSwift/Observables/Implementations/ObserveOnSerialDispatchQueue.swift @@ -18,28 +18,31 @@ public var numberOfSerialDispatchQueueObservables: Int32 = 0 #endif class ObserveOnSerialDispatchQueueSink : ObserverBase { - let scheduler: SerialDispatchQueueScheduler let observer: O let subscription = SingleAssignmentDisposable() - + + var cachedScheduleLambda: ((ObserveOnSerialDispatchQueueSink, Event) -> Disposable)! + init(scheduler: SerialDispatchQueueScheduler, observer: O) { self.scheduler = scheduler self.observer = observer super.init() + + cachedScheduleLambda = { sink, event in + sink.observer.on(event) + + if event.isStopEvent { + sink.dispose() + } + + return NopDisposable.instance + } } override func onCore(event: Event) { - self.scheduler.schedule(()) { (_) -> Disposable in - self.observer.on(event) - - if event.isStopEvent { - self.dispose() - } - - return NopDisposable.instance - } + self.scheduler.schedule((self, event), action: cachedScheduleLambda) } override func dispose() { From cd9f7654d55638784d8603333ff4e1c47a899fab Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 1 Nov 2015 22:12:52 +0100 Subject: [PATCH 17/19] Sink modifications. --- .../Observables/Implementations/Sink.swift | 25 ++++++------------- RxTests/PerformanceTests/main.swift | 10 ++++---- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/RxSwift/Observables/Implementations/Sink.swift b/RxSwift/Observables/Implementations/Sink.swift index e6ce7278..43527b69 100644 --- a/RxSwift/Observables/Implementations/Sink.swift +++ b/RxSwift/Observables/Implementations/Sink.swift @@ -9,18 +9,20 @@ import Foundation class Sink : SingleAssignmentDisposable { - private var _lock = SpinLock() - // state - private var _observer: O? + private var _observer: O var observer: O? { get { - _lock.lock(); defer { _lock.unlock() } + //_lock.lock(); defer { _lock.unlock() } return _observer } } - + + func forward(event: Event) { + _observer.on(event) + } + init(observer: O) { #if TRACE_RESOURCES OSAtomicIncrement32(&resourceCount) @@ -28,19 +30,6 @@ class Sink : SingleAssignmentDisposable { _observer = observer } - private func _disposeObserver() { - _lock.lock(); defer { _lock.unlock() } - - _observer = nil - } - - override func dispose() { - if !disposed { - _disposeObserver() - } - super.dispose() - } - deinit { #if TRACE_RESOURCES OSAtomicDecrement32(&resourceCount) diff --git a/RxTests/PerformanceTests/main.swift b/RxTests/PerformanceTests/main.swift index 1d80a525..f2a0b7f1 100644 --- a/RxTests/PerformanceTests/main.swift +++ b/RxTests/PerformanceTests/main.swift @@ -24,14 +24,14 @@ compareTwoImplementations(benchmarkTime: true, first: { //let a = just(1) //combineLatest(a, - publishSubject + publishSubject//.asDriver(onErrorJustReturn: -1) .shareReplay(1) .map { $0 } - .filter { _ in true }// ){ x, _ in x } - //.map { $0 } - //.flatMap { just($0) } + .filter { _ in true }//){ x, _ in x } + .map { $0 } + .flatMap { just($0) } .subscribeNext { _ in - + } From 59f3b487d213caf7196a5a23ebfb1b12b560a7dc Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Mon, 2 Nov 2015 00:17:11 +0100 Subject: [PATCH 18/19] Removes locks from sink forwarding (25% improvement). --- .../Services/ReachabilityService.swift | 2 +- RxSwift/Observables/Implementations/Amb.swift | 4 +-- .../Implementations/AnonymousObservable.swift | 4 +-- .../Observables/Implementations/Buffer.swift | 8 +++--- .../Observables/Implementations/Catch.swift | 16 +++++------ .../CombineLatest+CollectionType.swift | 10 +++---- .../Implementations/CombineLatest.swift | 10 +++---- .../Observables/Implementations/Concat.swift | 4 +-- .../Observables/Implementations/Debug.swift | 2 +- .../Implementations/Deferred.swift | 4 +-- .../Implementations/DelaySubscription.swift | 2 +- .../DistinctUntilChanged.swift | 6 ++--- RxSwift/Observables/Implementations/Do.swift | 4 +-- .../Implementations/ElementAt.swift | 12 ++++----- .../Observables/Implementations/Filter.swift | 6 ++--- .../Observables/Implementations/FlatMap.swift | 12 ++++----- .../Implementations/Generate.swift | 6 ++--- RxSwift/Observables/Implementations/Map.swift | 8 +++--- .../Observables/Implementations/Merge.swift | 20 +++++++------- .../Implementations/Multicast.swift | 4 +-- .../Observables/Implementations/Range.swift | 4 +-- .../Observables/Implementations/Reduce.swift | 10 +++---- .../Implementations/RefCount.swift | 4 +-- .../Observables/Implementations/Repeat.swift | 2 +- .../Observables/Implementations/Sample.swift | 12 ++++----- .../Observables/Implementations/Scan.swift | 8 +++--- .../Implementations/ShareReplay1.swift | 22 ++++++++------- .../Observables/Implementations/Sink.swift | 17 +++++------- .../Observables/Implementations/Skip.swift | 12 ++++----- .../Implementations/SkipUntil.swift | 23 +++++----------- .../Implementations/SkipWhile.swift | 12 ++++----- .../Implementations/SubscribeOn.swift | 2 +- .../Observables/Implementations/Switch.swift | 12 ++++----- .../Observables/Implementations/Take.swift | 16 +++++------ .../Implementations/TakeLast.swift | 6 ++--- .../Implementations/TakeUntil.swift | 27 +++++++------------ .../Implementations/TakeWhile.swift | 16 +++++------ .../Implementations/Throttle.swift | 8 +++--- .../Observables/Implementations/Timer.swift | 6 ++--- .../Observables/Implementations/ToArray.swift | 6 ++--- .../Observables/Implementations/Using.swift | 6 ++--- .../Implementations/WithLatestFrom.swift | 10 +++---- .../Implementations/Zip+CollectionType.swift | 10 +++---- RxSwift/Observables/Implementations/Zip.swift | 10 +++---- RxSwift/ObserverType.swift | 2 +- RxSwift/Observers/TailRecursiveSink.swift | 2 +- .../RxSwiftTests/Tests/ObserverTests.swift | 2 +- 47 files changed, 195 insertions(+), 216 deletions(-) diff --git a/RxExample/RxExample/Services/ReachabilityService.swift b/RxExample/RxExample/Services/ReachabilityService.swift index 8b702585..098dfd0d 100644 --- a/RxExample/RxExample/Services/ReachabilityService.swift +++ b/RxExample/RxExample/Services/ReachabilityService.swift @@ -48,7 +48,7 @@ extension ObservableConvertibleType { } func retryOnBecomesReachable(valueOnFailure:E, reachabilityService:ReachabilityService, orExternalTrigger: Observable) -> Observable{ - return self + return self.asObservable() .catchError { (e) -> Observable in let retryBecauseOfNeworkAvailability = reachabilityService.reachabilityChanged .flatMap { event -> Observable in diff --git a/RxSwift/Observables/Implementations/Amb.swift b/RxSwift/Observables/Implementations/Amb.swift index 439cbd65..8c54f786 100644 --- a/RxSwift/Observables/Implementations/Amb.swift +++ b/RxSwift/Observables/Implementations/Amb.swift @@ -69,7 +69,7 @@ class AmbSink : Sink { let disposeAll = StableCompositeDisposable.create(subscription1, subscription2) let forwardEvent = { (o: AmbObserverType, event: Event) -> Void in - self.observer?.on(event) + self.forwardOn(event) } let decide = { (o: AmbObserverType, event: Event, me: AmbState, otherSubscription: Disposable) in @@ -82,7 +82,7 @@ class AmbSink : Sink { } if self._choice == me { - self.observer?.on(event) + self.forwardOn(event) if event.isStopEvent { self.dispose() } diff --git a/RxSwift/Observables/Implementations/AnonymousObservable.swift b/RxSwift/Observables/Implementations/AnonymousObservable.swift index 506f8b31..eb23374a 100644 --- a/RxSwift/Observables/Implementations/AnonymousObservable.swift +++ b/RxSwift/Observables/Implementations/AnonymousObservable.swift @@ -26,10 +26,10 @@ class AnonymousObservableSink : Sink, ObserverType { if _isStopped == 1 { return } - observer?.on(event) + forwardOn(event) case .Error, .Completed: if OSAtomicCompareAndSwap32(0, 1, &_isStopped) { - self.observer?.on(event) + self.forwardOn(event) self.dispose() } } diff --git a/RxSwift/Observables/Implementations/Buffer.swift b/RxSwift/Observables/Implementations/Buffer.swift index 1c932ed3..b941e64f 100644 --- a/RxSwift/Observables/Implementations/Buffer.swift +++ b/RxSwift/Observables/Implementations/Buffer.swift @@ -62,7 +62,7 @@ class BufferTimeCountSink : ObserverType { } func on(event: Event) { - _parent.observer?.on(event) + _parent.forwardOn(event) switch event { case .Next: @@ -55,9 +55,9 @@ class CatchSink : Sink, ObserverType { func on(event: Event) { switch event { case .Next: - observer?.on(event) + forwardOn(event) case .Completed: - observer?.on(event) + forwardOn(event) dispose() case .Error(let error): do { @@ -68,7 +68,7 @@ class CatchSink : Sink, ObserverType { _subscription.disposable = catchSequence.subscribe(observer) } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() } } @@ -108,22 +108,22 @@ class CatchSequenceSink) { switch event { case .Next: - observer?.on(event) + forwardOn(event) case .Error(let error): _lastError = error scheduleMoveNext() case .Completed: - observer?.on(event) + forwardOn(event) dispose() } } override func done() { if let lastError = _lastError { - observer?.on(.Error(lastError)) + forwardOn(.Error(lastError)) } else { - observer?.on(.Completed) + forwardOn(.Completed) } self.dispose() diff --git a/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift b/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift index e1e2bb82..e91669b0 100644 --- a/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift +++ b/RxSwift/Observables/Implementations/CombineLatest+CollectionType.swift @@ -51,7 +51,7 @@ class CombineLatestCollectionTypeSink if _numberOfValues == _arity { do { let result = try getResult() - observer?.on(.Next(result)) + forwardOn(.Next(result)) } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() } } @@ -66,14 +66,14 @@ class CombineLatestSink } if allOthersDone { - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } } func fail(error: ErrorType) { - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() } @@ -86,7 +86,7 @@ class CombineLatestSink _numberOfDone++ if _numberOfDone == _arity { - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } diff --git a/RxSwift/Observables/Implementations/Concat.swift b/RxSwift/Observables/Implementations/Concat.swift index c9aca4e8..9aac20b0 100644 --- a/RxSwift/Observables/Implementations/Concat.swift +++ b/RxSwift/Observables/Implementations/Concat.swift @@ -19,9 +19,9 @@ class ConcatSink){ switch event { case .Next: - observer?.on(event) + forwardOn(event) case .Error: - observer?.on(event) + forwardOn(event) dispose() case .Completed: scheduleMoveNext() diff --git a/RxSwift/Observables/Implementations/Debug.swift b/RxSwift/Observables/Implementations/Debug.swift index 090849cd..8b125f9c 100644 --- a/RxSwift/Observables/Implementations/Debug.swift +++ b/RxSwift/Observables/Implementations/Debug.swift @@ -26,7 +26,7 @@ class Debug_ : Sink, ObserverType { ? String(eventText.characters.prefix(maxEventTextLength / 2)) + "..." + String(eventText.characters.suffix(maxEventTextLength / 2)) : eventText print("[\(_parent._identifier)] -> Event \(eventNormalized)") - observer?.on(event) + forwardOn(event) } override func dispose() { diff --git a/RxSwift/Observables/Implementations/Deferred.swift b/RxSwift/Observables/Implementations/Deferred.swift index 92b71788..7e526338 100644 --- a/RxSwift/Observables/Implementations/Deferred.swift +++ b/RxSwift/Observables/Implementations/Deferred.swift @@ -25,14 +25,14 @@ class DeferredSink : Sink, ObserverType { return result.subscribe(self) } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() return NopDisposable.instance } } func on(event: Event) { - observer?.on(event) + forwardOn(event) switch event { case .Next: diff --git a/RxSwift/Observables/Implementations/DelaySubscription.swift b/RxSwift/Observables/Implementations/DelaySubscription.swift index 147fd032..755a07f0 100644 --- a/RxSwift/Observables/Implementations/DelaySubscription.swift +++ b/RxSwift/Observables/Implementations/DelaySubscription.swift @@ -22,7 +22,7 @@ class DelaySubscriptionSink) { - observer?.on(event) + forwardOn(event) if event.isStopEvent { dispose() } diff --git a/RxSwift/Observables/Implementations/DistinctUntilChanged.swift b/RxSwift/Observables/Implementations/DistinctUntilChanged.swift index d0ab70cf..46b75b98 100644 --- a/RxSwift/Observables/Implementations/DistinctUntilChanged.swift +++ b/RxSwift/Observables/Implementations/DistinctUntilChanged.swift @@ -37,14 +37,14 @@ class DistinctUntilChangedSink: Sink, ObserverType { _currentKey = key - observer?.on(event) + forwardOn(event) } catch let error { - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() } case .Error, .Completed: - observer?.on(event) + forwardOn(event) dispose() } } diff --git a/RxSwift/Observables/Implementations/Do.swift b/RxSwift/Observables/Implementations/Do.swift index 5f163cf6..0680c9ab 100644 --- a/RxSwift/Observables/Implementations/Do.swift +++ b/RxSwift/Observables/Implementations/Do.swift @@ -22,13 +22,13 @@ class DoSink : Sink, ObserverType { func on(event: Event) { do { try _parent._eventHandler(event) - observer?.on(event) + forwardOn(event) if event.isStopEvent { dispose() } } catch let error { - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() } } diff --git a/RxSwift/Observables/Implementations/ElementAt.swift b/RxSwift/Observables/Implementations/ElementAt.swift index 19401b2c..4360afb1 100644 --- a/RxSwift/Observables/Implementations/ElementAt.swift +++ b/RxSwift/Observables/Implementations/ElementAt.swift @@ -27,27 +27,27 @@ class ElementAtSink : Sink< case .Next(_): if (_i == 0) { - observer?.on(event) - observer?.on(.Completed) + forwardOn(event) + forwardOn(.Completed) self.dispose() } do { try decrementChecked(&_i) } catch(let e) { - observer?.onError(e) + forwardOn(.Error(e)) dispose() return } case .Error(let e): - observer?.on(.Error(e)) + forwardOn(.Error(e)) self.dispose() case .Completed: if (_parent._throwOnEmpty) { - observer?.onError(RxError.ArgumentOutOfRange) + forwardOn(.Error(RxError.ArgumentOutOfRange)) } else { - observer?.on(.Completed) + forwardOn(.Completed) } self.dispose() diff --git a/RxSwift/Observables/Implementations/Filter.swift b/RxSwift/Observables/Implementations/Filter.swift index 8efda19b..3f3f0133 100644 --- a/RxSwift/Observables/Implementations/Filter.swift +++ b/RxSwift/Observables/Implementations/Filter.swift @@ -26,15 +26,15 @@ class FilterSink: Sink, ObserverType { do { let satisfies = try _parent._predicate(value) if satisfies { - observer?.on(.Next(value)) + forwardOn(.Next(value)) } } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() } case .Completed, .Error: - observer?.on(event) + forwardOn(event) dispose() } } diff --git a/RxSwift/Observables/Implementations/FlatMap.swift b/RxSwift/Observables/Implementations/FlatMap.swift index f9383df3..a00a6209 100644 --- a/RxSwift/Observables/Implementations/FlatMap.swift +++ b/RxSwift/Observables/Implementations/FlatMap.swift @@ -28,11 +28,11 @@ class FlatMapSinkIter : Sink { if try self._parent._condition(self._state) { let result = try self._parent._resultSelector(self._state) - self.observer?.on(.Next(result)) + self.forwardOn(.Next(result)) recurse(false) } else { - self.observer?.on(.Completed) + self.forwardOn(.Completed) self.dispose() } } catch let error { - self.observer?.on(.Error(error)) + self.forwardOn(.Error(error)) self.dispose() } } diff --git a/RxSwift/Observables/Implementations/Map.swift b/RxSwift/Observables/Implementations/Map.swift index e7817cbe..66424cba 100644 --- a/RxSwift/Observables/Implementations/Map.swift +++ b/RxSwift/Observables/Implementations/Map.swift @@ -31,17 +31,17 @@ class MapSink : Sink, ObserverType { case .Next(let element): do { let mappedElement = try performMap(element) - observer?.on(.Next(mappedElement)) + forwardOn(.Next(mappedElement)) } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() } case .Error(let error): - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() case .Completed: - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } diff --git a/RxSwift/Observables/Implementations/Merge.swift b/RxSwift/Observables/Implementations/Merge.swift index a0b996ba..d2d97e5b 100644 --- a/RxSwift/Observables/Implementations/Merge.swift +++ b/RxSwift/Observables/Implementations/Merge.swift @@ -37,15 +37,15 @@ class MergeSinkIter) { switch event { case .Next: - _parent.observer?.on(event) + _parent.forwardOn(event) case .Error: - _parent.observer?.on(event) + _parent.forwardOn(event) _parent.dispose() case .Completed: _parent._group.removeDisposable(_disposeKey) if _parent._stopped && _parent._group.count == 1 { - _parent.observer?.on(.Completed) + _parent.forwardOn(.Completed) _parent.dispose() } } @@ -107,13 +107,13 @@ class MergeSink case .Next: rxFatalError("Next should have been handled") case .Error(let error): - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() case .Completed: _stopped = true if _group.count == 1 { - observer?.on(.Completed) + forwardOn(.Completed) dispose() } else { @@ -152,9 +152,9 @@ class MergeConcurrentSinkIter) { switch event { case .Next: - _parent.observer?.on(event) + _parent.forwardOn(event) case .Error: - _parent.observer?.on(event) + _parent.forwardOn(event) _parent.dispose() case .Completed: _parent._group.removeDisposable(_disposeKey) @@ -167,7 +167,7 @@ class MergeConcurrentSinkIter: Sink, ObserverType { return BinaryDisposable(subscription, connection) } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() return NopDisposable.instance } } func on(event: Event) { - observer?.on(event) + forwardOn(event) switch event { case .Next: break case .Error, .Completed: diff --git a/RxSwift/Observables/Implementations/Range.swift b/RxSwift/Observables/Implementations/Range.swift index 8093416a..17277244 100644 --- a/RxSwift/Observables/Implementations/Range.swift +++ b/RxSwift/Observables/Implementations/Range.swift @@ -47,11 +47,11 @@ class RangeSink<_CompilerWorkaround, O: ObserverType where O.E == Int> : Sink func run() -> Disposable { return _parent._scheduler.scheduleRecursive(0) { i, recurse in if i < self._parent._count { - self.observer?.on(.Next(self._parent._start + i)) + self.forwardOn(.Next(self._parent._start + i)) recurse(i + 1) } else { - self.observer?.on(.Completed) + self.forwardOn(.Completed) self.dispose() } } diff --git a/RxSwift/Observables/Implementations/Reduce.swift b/RxSwift/Observables/Implementations/Reduce.swift index 3276b326..792f3cd6 100644 --- a/RxSwift/Observables/Implementations/Reduce.swift +++ b/RxSwift/Observables/Implementations/Reduce.swift @@ -29,21 +29,21 @@ class ReduceSink : Sink, Observe _accumulation = try _parent._accumulator(_accumulation, value) } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() } case .Error(let e): - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() case .Completed: do { let result = try _parent._mapResult(_accumulation) - observer?.on(.Next(result)) - observer?.on(.Completed) + forwardOn(.Next(result)) + forwardOn(.Completed) dispose() } catch let e { - observer?.on(.Error(e)) + forwardOn(.Error(e)) dispose() } } diff --git a/RxSwift/Observables/Implementations/RefCount.swift b/RxSwift/Observables/Implementations/RefCount.swift index 4216aefa..904c02c7 100644 --- a/RxSwift/Observables/Implementations/RefCount.swift +++ b/RxSwift/Observables/Implementations/RefCount.swift @@ -55,9 +55,9 @@ class RefCountSink) { switch event { case .Next: - observer?.on(event) + forwardOn(event) case .Error, .Completed: - observer?.on(event) + forwardOn(event) dispose() } } diff --git a/RxSwift/Observables/Implementations/Repeat.swift b/RxSwift/Observables/Implementations/Repeat.swift index 8655d929..13b9cc72 100644 --- a/RxSwift/Observables/Implementations/Repeat.swift +++ b/RxSwift/Observables/Implementations/Repeat.swift @@ -37,7 +37,7 @@ class RepeatElementSink : Sink { func run() -> Disposable { return _parent._scheduler.scheduleRecursive(_parent._element) { e, recurse in - self.observer?.on(.Next(e)) + self.forwardOn(.Next(e)) recurse(e) } } diff --git a/RxSwift/Observables/Implementations/Sample.swift b/RxSwift/Observables/Implementations/Sample.swift index 703b86e1..3c9c7bb4 100644 --- a/RxSwift/Observables/Implementations/Sample.swift +++ b/RxSwift/Observables/Implementations/Sample.swift @@ -38,23 +38,23 @@ class SamplerSink case .Next(let element): _element = element case .Error: - observer?.on(event) + forwardOn(event) dispose() case .Completed: _atEnd = true diff --git a/RxSwift/Observables/Implementations/Scan.swift b/RxSwift/Observables/Implementations/Scan.swift index 9f0f5feb..406fbd5a 100644 --- a/RxSwift/Observables/Implementations/Scan.swift +++ b/RxSwift/Observables/Implementations/Scan.swift @@ -26,17 +26,17 @@ class ScanSink case .Next(let element): do { _accumulate = try _parent._accumulator(_accumulate, element) - observer?.on(.Next(_accumulate)) + forwardOn(.Next(_accumulate)) } catch let error { - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() } case .Error(let error): - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() case .Completed: - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } diff --git a/RxSwift/Observables/Implementations/ShareReplay1.swift b/RxSwift/Observables/Implementations/ShareReplay1.swift index ba478eea..0707b840 100644 --- a/RxSwift/Observables/Implementations/ShareReplay1.swift +++ b/RxSwift/Observables/Implementations/ShareReplay1.swift @@ -23,7 +23,7 @@ class ShareReplay1 let _lock = NSRecursiveLock() - private var _subscription: Disposable? + private var _connection: SingleAssignmentDisposable? private var _element: Element? private var _stopEvent = nil as Event? private var _observers = Bag>() @@ -32,7 +32,6 @@ class ShareReplay1 self._source = source } - override func subscribe(observer: O) -> Disposable { return synchronizedSubscribe(observer) } @@ -52,7 +51,10 @@ class ShareReplay1 let disposeKey = self._observers.insert(AnyObserver(observer)) if initialCount == 0 { - self._subscription = self._source.subscribe(self) + let connection = SingleAssignmentDisposable() + _connection = connection + + connection.disposable = self._source.subscribe(self) } return SubscriptionDisposable(owner: self, key: disposeKey) @@ -64,9 +66,9 @@ class ShareReplay1 return } - if self._observers.count == 0 { - self._subscription?.dispose() - self._subscription = nil + if _observers.count == 0 { + _connection?.dispose() + _connection = nil } } @@ -75,16 +77,18 @@ class ShareReplay1 } func _synchronized_on(event: Event) { - if self._stopEvent != nil { + if _stopEvent != nil { return } if case .Next(let element) = event { - self._element = element + _element = element } if event.isStopEvent { - self._stopEvent = event + _stopEvent = event + _connection?.dispose() + _connection = nil } _observers.on(event) diff --git a/RxSwift/Observables/Implementations/Sink.swift b/RxSwift/Observables/Implementations/Sink.swift index 43527b69..debaf0aa 100644 --- a/RxSwift/Observables/Implementations/Sink.swift +++ b/RxSwift/Observables/Implementations/Sink.swift @@ -9,25 +9,20 @@ import Foundation class Sink : SingleAssignmentDisposable { - // state - private var _observer: O + let observer: O - var observer: O? { - get { - //_lock.lock(); defer { _lock.unlock() } - return _observer + func forwardOn(event: Event) { + if disposed { + return } - } - - func forward(event: Event) { - _observer.on(event) + observer.on(event) } init(observer: O) { #if TRACE_RESOURCES OSAtomicIncrement32(&resourceCount) #endif - _observer = observer + self.observer = observer } deinit { diff --git a/RxSwift/Observables/Implementations/Skip.swift b/RxSwift/Observables/Implementations/Skip.swift index 8d4ddc53..5c8095d5 100644 --- a/RxSwift/Observables/Implementations/Skip.swift +++ b/RxSwift/Observables/Implementations/Skip.swift @@ -29,16 +29,16 @@ class SkipCountSink : Sin case .Next(let value): if remaining <= 0 { - observer?.on(.Next(value)) + forwardOn(.Next(value)) } else { remaining-- } case .Error: - observer?.on(event) + forwardOn(event) self.dispose() case .Completed: - observer?.on(event) + forwardOn(event) self.dispose() } } @@ -82,13 +82,13 @@ class SkipTimeSink : Sin do { _running = try !_parent._predicate(value) } catch let e { - observer?.onError(e) + forwardOn(.Error(e)) dispose() return } } if _running { - observer?.onNext(value) + forwardOn(.Next(value)) } case .Error, .Completed: - observer?.on(event) + forwardOn(event) dispose() } } @@ -64,17 +64,17 @@ class SkipWhileSinkWithIndex : S } func on(event: Event) { - observer?.on(event) + forwardOn(event) if event.isStopEvent { self.dispose() diff --git a/RxSwift/Observables/Implementations/Switch.swift b/RxSwift/Observables/Implementations/Switch.swift index db5b7662..e6048649 100644 --- a/RxSwift/Observables/Implementations/Switch.swift +++ b/RxSwift/Observables/Implementations/Switch.swift @@ -57,7 +57,7 @@ class SwitchSink let disposable = observable.asObservable().subscribe(observer) d.disposable = disposable case .Error(let error): - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() case .Completed: _stopped = true @@ -65,7 +65,7 @@ class SwitchSink _subscriptions.dispose() if !_hasLatest { - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } @@ -108,18 +108,16 @@ class SwitchSinkIter : Sin if _remaining > 0 { _remaining-- - observer?.on(.Next(value)) + forwardOn(.Next(value)) if _remaining == 0 { - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } case .Error: - observer?.on(event) + forwardOn(event) dispose() case .Completed: - observer?.on(event) + forwardOn(event) dispose() } } @@ -94,12 +94,12 @@ class TakeTimeSink) { switch event { case .Next(let value): - observer?.on(.Next(value)) + forwardOn(.Next(value)) case .Error: - observer?.on(event) + forwardOn(event) dispose() case .Completed: - observer?.on(event) + forwardOn(event) dispose() } } @@ -107,7 +107,7 @@ class TakeTimeSink : Sink _elements.dequeue() } case .Error: - observer?.on(event) + forwardOn(event) dispose() case .Completed: for e in _elements { - observer?.on(.Next(e)) + forwardOn(.Next(e)) } - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } diff --git a/RxSwift/Observables/Implementations/TakeUntil.swift b/RxSwift/Observables/Implementations/TakeUntil.swift index 21f492d1..4820b720 100644 --- a/RxSwift/Observables/Implementations/TakeUntil.swift +++ b/RxSwift/Observables/Implementations/TakeUntil.swift @@ -21,16 +21,7 @@ class TakeUntilSinkOther) { switch event { case .Next: - _parent.observer?.on(.Completed) + _parent.forwardOn(.Completed) _parent.dispose() case .Error(let e): - _parent.observer?.on(.Error(e)) + _parent.forwardOn(.Error(e)) _parent.dispose() case .Completed: _parent._open = true - _singleAssignmentDisposable.dispose() + _subscription.dispose() } } @@ -91,12 +82,12 @@ class TakeUntilSink) { switch event { case .Next: - observer?.on(event) + forwardOn(event) case .Error: - observer?.on(event) + forwardOn(event) dispose() case .Completed: - observer?.on(event) + forwardOn(event) dispose() } } @@ -104,10 +95,10 @@ class TakeUntilSink Disposable { let otherObserver = TakeUntilSinkOther(parent: self) let otherSubscription = _parent._other.subscribe(otherObserver) - otherObserver.disposable = otherSubscription + otherObserver._subscription.disposable = otherSubscription let sourceSubscription = _parent._source.subscribe(self) - return StableCompositeDisposable.create(sourceSubscription, otherSubscription) + return StableCompositeDisposable.create(sourceSubscription, otherObserver._subscription) } } diff --git a/RxSwift/Observables/Implementations/TakeWhile.swift b/RxSwift/Observables/Implementations/TakeWhile.swift index 80dadf94..7e395564 100644 --- a/RxSwift/Observables/Implementations/TakeWhile.swift +++ b/RxSwift/Observables/Implementations/TakeWhile.swift @@ -33,19 +33,19 @@ class TakeWhileSink do { _running = try _parent._predicate(value) } catch let e { - observer?.onError(e) + forwardOn(.Error(e)) dispose() return } if _running { - observer?.onNext(value) + forwardOn(.Next(value)) } else { - observer?.onComplete() + forwardOn(.Completed) dispose() } case .Error, .Completed: - observer?.on(event) + forwardOn(event) dispose() } } @@ -79,19 +79,19 @@ class TakeWhileSinkWithIndex d.disposable = scheduler.scheduleRelative(currentId, dueTime: dueTime, action: self.propagate) case .Error: _value = nil - observer?.on(event) + forwardOn(event) dispose() case .Completed: if let value = _value { _value = nil - observer?.on(.Next(value)) + forwardOn(.Next(value)) } - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } @@ -76,7 +76,7 @@ class ThrottleSink if let value = originalValue where _id == currentId { _value = nil - observer?.on(.Next(value)) + forwardOn(.Next(value)) } // } return NopDisposable.instance diff --git a/RxSwift/Observables/Implementations/Timer.swift b/RxSwift/Observables/Implementations/Timer.swift index f6b7d724..d334d0c4 100644 --- a/RxSwift/Observables/Implementations/Timer.swift +++ b/RxSwift/Observables/Implementations/Timer.swift @@ -20,7 +20,7 @@ class TimerSink : Sink func run() -> Disposable { return _parent._scheduler.schedulePeriodic(0 as Int64, startAfter: _parent._dueTime, period: _parent._period!) { state in - self.observer?.on(.Next(state)) + self.forwardOn(.Next(state)) return state &+ 1 } } @@ -38,8 +38,8 @@ class TimerOneOffSink : Si func run() -> Disposable { return _parent._scheduler.scheduleRelative((), dueTime: _parent._dueTime) { (_) -> Disposable in - self.observer?.on(.Next(0)) - self.observer?.on(.Completed) + self.forwardOn(.Next(0)) + self.forwardOn(.Completed) return NopDisposable.instance } diff --git a/RxSwift/Observables/Implementations/ToArray.swift b/RxSwift/Observables/Implementations/ToArray.swift index 1b514d26..bac43dbd 100644 --- a/RxSwift/Observables/Implementations/ToArray.swift +++ b/RxSwift/Observables/Implementations/ToArray.swift @@ -25,11 +25,11 @@ class ToArraySink : Sink< case .Next(let value): self._list.append(value) case .Error(let e): - observer?.on(.Error(e)) + forwardOn(.Error(e)) self.dispose() case .Completed: - observer?.on(.Next(_list)) - observer?.on(.Completed) + forwardOn(.Next(_list)) + forwardOn(.Completed) self.dispose() } } diff --git a/RxSwift/Observables/Implementations/Using.swift b/RxSwift/Observables/Implementations/Using.swift index ed4a891a..628167f3 100644 --- a/RxSwift/Observables/Implementations/Using.swift +++ b/RxSwift/Observables/Implementations/Using.swift @@ -43,12 +43,12 @@ class UsingSink) { switch event { case let .Next(value): - observer?.onNext(value) + forwardOn(.Next(value)) case let .Error(error): - observer?.onError(error) + forwardOn(.Error(error)) dispose() case .Completed: - observer?.onComplete() + forwardOn(.Completed) dispose() } } diff --git a/RxSwift/Observables/Implementations/WithLatestFrom.swift b/RxSwift/Observables/Implementations/WithLatestFrom.swift index 685c56d7..a312456b 100644 --- a/RxSwift/Observables/Implementations/WithLatestFrom.swift +++ b/RxSwift/Observables/Implementations/WithLatestFrom.swift @@ -49,16 +49,16 @@ class WithLatestFromSink : Sink, ZipSinkProtocol { if hasValueAll { do { let result = try getResult() - self.observer?.on(.Next(result)) + self.forwardOn(.Next(result)) } catch let e { - self.observer?.on(.Error(e)) + self.forwardOn(.Error(e)) dispose() } } @@ -72,14 +72,14 @@ class ZipSink : Sink, ZipSinkProtocol { } if allOthersDone { - observer?.on(.Completed) + forwardOn(.Completed) self.dispose() } } } func fail(error: ErrorType) { - observer?.on(.Error(error)) + forwardOn(.Error(error)) dispose() } @@ -96,7 +96,7 @@ class ZipSink : Sink, ZipSinkProtocol { } if allDone { - observer?.on(.Completed) + forwardOn(.Completed) dispose() } } diff --git a/RxSwift/ObserverType.swift b/RxSwift/ObserverType.swift index e609fff7..642f75fd 100644 --- a/RxSwift/ObserverType.swift +++ b/RxSwift/ObserverType.swift @@ -42,7 +42,7 @@ public extension ObserverType { /** Convienence method equivalent to `on(.Completed)` */ - final func onComplete() { + final func onCompleted() { on(.Completed) } diff --git a/RxSwift/Observers/TailRecursiveSink.swift b/RxSwift/Observers/TailRecursiveSink.swift index c4021064..c650b89b 100644 --- a/RxSwift/Observers/TailRecursiveSink.swift +++ b/RxSwift/Observers/TailRecursiveSink.swift @@ -49,7 +49,7 @@ class TailRecursiveSink Date: Mon, 2 Nov 2015 00:41:01 +0100 Subject: [PATCH 19/19] Makes `observer` in `Sink` private again. --- .../Observables/Implementations/DistinctUntilChanged.swift | 2 -- RxSwift/Observables/Implementations/FlatMap.swift | 2 -- RxSwift/Observables/Implementations/Map.swift | 2 -- RxSwift/Observables/Implementations/Sink.swift | 6 +++--- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/RxSwift/Observables/Implementations/DistinctUntilChanged.swift b/RxSwift/Observables/Implementations/DistinctUntilChanged.swift index 46b75b98..ae9f6192 100644 --- a/RxSwift/Observables/Implementations/DistinctUntilChanged.swift +++ b/RxSwift/Observables/Implementations/DistinctUntilChanged.swift @@ -20,8 +20,6 @@ class DistinctUntilChangedSink: Sink, ObserverType { } func on(event: Event) { - let observer = super.observer - switch event { case .Next(let value): do { diff --git a/RxSwift/Observables/Implementations/FlatMap.swift b/RxSwift/Observables/Implementations/FlatMap.swift index a00a6209..458c7cef 100644 --- a/RxSwift/Observables/Implementations/FlatMap.swift +++ b/RxSwift/Observables/Implementations/FlatMap.swift @@ -77,8 +77,6 @@ class FlatMapSink) { - let observer = super.observer - switch event { case .Next(let element): do { diff --git a/RxSwift/Observables/Implementations/Map.swift b/RxSwift/Observables/Implementations/Map.swift index 66424cba..20c6bd1a 100644 --- a/RxSwift/Observables/Implementations/Map.swift +++ b/RxSwift/Observables/Implementations/Map.swift @@ -25,8 +25,6 @@ class MapSink : Sink, ObserverType { } func on(event: Event) { - let observer = super.observer - switch event { case .Next(let element): do { diff --git a/RxSwift/Observables/Implementations/Sink.swift b/RxSwift/Observables/Implementations/Sink.swift index debaf0aa..fec16dd0 100644 --- a/RxSwift/Observables/Implementations/Sink.swift +++ b/RxSwift/Observables/Implementations/Sink.swift @@ -9,20 +9,20 @@ import Foundation class Sink : SingleAssignmentDisposable { - let observer: O + private let _observer: O func forwardOn(event: Event) { if disposed { return } - observer.on(event) + _observer.on(event) } init(observer: O) { #if TRACE_RESOURCES OSAtomicIncrement32(&resourceCount) #endif - self.observer = observer + _observer = observer } deinit {