mirror of
https://github.com/ReactiveX/RxSwift.git
synced 2024-10-05 14:37:29 +03:00
Blocking operators run runloop while blocking.
This commit is contained in:
parent
e39f5dbce1
commit
d4cda2430e
@ -358,6 +358,10 @@
|
|||||||
C88254341B8A752B00B02D69 /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254121B8A752B00B02D69 /* UITableView+Rx.swift */; };
|
C88254341B8A752B00B02D69 /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254121B8A752B00B02D69 /* UITableView+Rx.swift */; };
|
||||||
C88254351B8A752B00B02D69 /* UITextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254131B8A752B00B02D69 /* UITextField+Rx.swift */; };
|
C88254351B8A752B00B02D69 /* UITextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254131B8A752B00B02D69 /* UITextField+Rx.swift */; };
|
||||||
C88254361B8A752B00B02D69 /* UITextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254141B8A752B00B02D69 /* UITextView+Rx.swift */; };
|
C88254361B8A752B00B02D69 /* UITextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254141B8A752B00B02D69 /* UITextView+Rx.swift */; };
|
||||||
|
C88E296B1BEB712E001CCB92 /* RunLoopLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88E296A1BEB712E001CCB92 /* RunLoopLock.swift */; };
|
||||||
|
C88E296C1BEB712E001CCB92 /* RunLoopLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88E296A1BEB712E001CCB92 /* RunLoopLock.swift */; };
|
||||||
|
C88E296D1BEB712E001CCB92 /* RunLoopLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88E296A1BEB712E001CCB92 /* RunLoopLock.swift */; };
|
||||||
|
C88E296E1BEB712E001CCB92 /* RunLoopLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88E296A1BEB712E001CCB92 /* RunLoopLock.swift */; };
|
||||||
C8941BDF1BD5695C00A0E874 /* BlockingObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */; };
|
C8941BDF1BD5695C00A0E874 /* BlockingObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */; };
|
||||||
C8941BE01BD5695C00A0E874 /* BlockingObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */; };
|
C8941BE01BD5695C00A0E874 /* BlockingObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */; };
|
||||||
C8941BE11BD5695C00A0E874 /* BlockingObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */; };
|
C8941BE11BD5695C00A0E874 /* BlockingObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */; };
|
||||||
@ -1001,6 +1005,7 @@
|
|||||||
C88254131B8A752B00B02D69 /* UITextField+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextField+Rx.swift"; sourceTree = "<group>"; };
|
C88254131B8A752B00B02D69 /* UITextField+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextField+Rx.swift"; sourceTree = "<group>"; };
|
||||||
C88254141B8A752B00B02D69 /* UITextView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextView+Rx.swift"; sourceTree = "<group>"; };
|
C88254141B8A752B00B02D69 /* UITextView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextView+Rx.swift"; sourceTree = "<group>"; };
|
||||||
C88BB8711B07E5ED0064D411 /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
C88BB8711B07E5ED0064D411 /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
C88E296A1BEB712E001CCB92 /* RunLoopLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RunLoopLock.swift; sourceTree = "<group>"; };
|
||||||
C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockingObservable.swift; sourceTree = "<group>"; };
|
C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockingObservable.swift; sourceTree = "<group>"; };
|
||||||
C8941BE31BD56B0700A0E874 /* BlockingObservable+Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BlockingObservable+Operators.swift"; sourceTree = "<group>"; };
|
C8941BE31BD56B0700A0E874 /* BlockingObservable+Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BlockingObservable+Operators.swift"; sourceTree = "<group>"; };
|
||||||
C89CDB351BCB0DD7002063D9 /* ShareReplay1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ShareReplay1.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
C89CDB351BCB0DD7002063D9 /* ShareReplay1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ShareReplay1.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||||
@ -1400,6 +1405,7 @@
|
|||||||
C8093F581B8A73A20088E94D /* ObservableConvertibleType+Blocking.swift */,
|
C8093F581B8A73A20088E94D /* ObservableConvertibleType+Blocking.swift */,
|
||||||
C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */,
|
C8941BDE1BD5695C00A0E874 /* BlockingObservable.swift */,
|
||||||
C8941BE31BD56B0700A0E874 /* BlockingObservable+Operators.swift */,
|
C8941BE31BD56B0700A0E874 /* BlockingObservable+Operators.swift */,
|
||||||
|
C88E296A1BEB712E001CCB92 /* RunLoopLock.swift */,
|
||||||
C8093F591B8A73A20088E94D /* README.md */,
|
C8093F591B8A73A20088E94D /* README.md */,
|
||||||
);
|
);
|
||||||
path = RxBlocking;
|
path = RxBlocking;
|
||||||
@ -2121,6 +2127,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
C88E296B1BEB712E001CCB92 /* RunLoopLock.swift in Sources */,
|
||||||
C8941BDF1BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
C8941BDF1BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
||||||
C8941BE41BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
C8941BE41BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
||||||
C8093F5E1B8A73A20088E94D /* ObservableConvertibleType+Blocking.swift in Sources */,
|
C8093F5E1B8A73A20088E94D /* ObservableConvertibleType+Blocking.swift in Sources */,
|
||||||
@ -2131,6 +2138,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
C88E296C1BEB712E001CCB92 /* RunLoopLock.swift in Sources */,
|
||||||
C8941BE01BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
C8941BE01BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
||||||
C8941BE51BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
C8941BE51BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
||||||
C8093F5F1B8A73A20088E94D /* ObservableConvertibleType+Blocking.swift in Sources */,
|
C8093F5F1B8A73A20088E94D /* ObservableConvertibleType+Blocking.swift in Sources */,
|
||||||
@ -2595,6 +2603,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
C88E296E1BEB712E001CCB92 /* RunLoopLock.swift in Sources */,
|
||||||
C8941BE21BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
C8941BE21BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
||||||
C8941BE71BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
C8941BE71BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
||||||
C8F0C04F1BBBFBCE001B112F /* ObservableConvertibleType+Blocking.swift in Sources */,
|
C8F0C04F1BBBFBCE001B112F /* ObservableConvertibleType+Blocking.swift in Sources */,
|
||||||
@ -2803,6 +2812,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
C88E296D1BEB712E001CCB92 /* RunLoopLock.swift in Sources */,
|
||||||
C8941BE11BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
C8941BE11BD5695C00A0E874 /* BlockingObservable.swift in Sources */,
|
||||||
C8941BE61BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
C8941BE61BD56B0700A0E874 /* BlockingObservable+Operators.swift in Sources */,
|
||||||
D2EBEB8A1BB9B9EE003A27DC /* ObservableConvertibleType+Blocking.swift in Sources */,
|
D2EBEB8A1BB9B9EE003A27DC /* ObservableConvertibleType+Blocking.swift in Sources */,
|
||||||
|
@ -13,44 +13,39 @@ import Foundation
|
|||||||
|
|
||||||
extension BlockingObservable {
|
extension BlockingObservable {
|
||||||
/**
|
/**
|
||||||
Blocks current thread until sequence terminates.
|
Blocks current thread until sequence terminates.
|
||||||
|
|
||||||
If sequence terminates with error, terminating error will be thrown.
|
|
||||||
|
|
||||||
- returns: All elements of sequence.
|
|
||||||
*/
|
|
||||||
public func toArray() throws -> [E] {
|
|
||||||
let condition = NSCondition()
|
|
||||||
|
|
||||||
var elements: [E] = Array<E>()
|
|
||||||
|
|
||||||
var error: ErrorType?
|
|
||||||
|
|
||||||
var ended = false
|
|
||||||
|
|
||||||
_ = self.source.subscribe { e in
|
If sequence terminates with error, terminating error will be thrown.
|
||||||
switch e {
|
|
||||||
case .Next(let element):
|
- returns: All elements of sequence.
|
||||||
elements.append(element)
|
*/
|
||||||
case .Error(let e):
|
public func toArray() throws -> [E] {
|
||||||
error = e
|
var elements: [E] = Array<E>()
|
||||||
condition.lock()
|
|
||||||
ended = true
|
var error: ErrorType?
|
||||||
condition.signal()
|
|
||||||
condition.unlock()
|
let lock = RunLoopLock()
|
||||||
case .Completed:
|
|
||||||
condition.lock()
|
let d = SingleAssignmentDisposable()
|
||||||
ended = true
|
|
||||||
condition.signal()
|
lock.dispatch {
|
||||||
condition.unlock()
|
d.disposable = self.source.subscribe { e in
|
||||||
|
switch e {
|
||||||
|
case .Next(let element):
|
||||||
|
elements.append(element)
|
||||||
|
case .Error(let e):
|
||||||
|
error = e
|
||||||
|
lock.stop()
|
||||||
|
case .Completed:
|
||||||
|
lock.stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
condition.lock()
|
|
||||||
while !ended {
|
lock.run()
|
||||||
condition.wait()
|
|
||||||
}
|
d.dispose()
|
||||||
condition.unlock()
|
|
||||||
|
|
||||||
if let error = error {
|
if let error = error {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
@ -61,99 +56,87 @@ extension BlockingObservable {
|
|||||||
|
|
||||||
extension BlockingObservable {
|
extension BlockingObservable {
|
||||||
/**
|
/**
|
||||||
Blocks current thread until sequence produces first element.
|
Blocks current thread until sequence produces first element.
|
||||||
|
|
||||||
If sequence terminates with error before producing first element, terminating error will be thrown.
|
If sequence terminates with error before producing first element, terminating error will be thrown.
|
||||||
|
|
||||||
- returns: First element of sequence. If sequence is empty `nil` is returned.
|
- returns: First element of sequence. If sequence is empty `nil` is returned.
|
||||||
*/
|
*/
|
||||||
public func first() throws -> E? {
|
public func first() throws -> E? {
|
||||||
let condition = NSCondition()
|
|
||||||
|
|
||||||
var element: E?
|
var element: E?
|
||||||
|
|
||||||
var error: ErrorType?
|
var error: ErrorType?
|
||||||
|
|
||||||
var ended = false
|
|
||||||
|
|
||||||
let d = SingleAssignmentDisposable()
|
let d = SingleAssignmentDisposable()
|
||||||
|
|
||||||
d.disposable = self.source.subscribe { e in
|
let lock = RunLoopLock()
|
||||||
switch e {
|
|
||||||
case .Next(let e):
|
lock.dispatch {
|
||||||
if element == nil {
|
d.disposable = self.source.subscribe { e in
|
||||||
element = e
|
switch e {
|
||||||
|
case .Next(let e):
|
||||||
|
if element == nil {
|
||||||
|
element = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case .Error(let e):
|
||||||
|
error = e
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
break
|
|
||||||
case .Error(let e):
|
lock.stop()
|
||||||
error = e
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
condition.lock()
|
|
||||||
ended = true
|
|
||||||
condition.signal()
|
|
||||||
condition.unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
condition.lock()
|
|
||||||
while !ended {
|
|
||||||
condition.wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock.run()
|
||||||
|
|
||||||
d.dispose()
|
d.dispose()
|
||||||
condition.unlock()
|
|
||||||
|
|
||||||
if let error = error {
|
if let error = error {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BlockingObservable {
|
extension BlockingObservable {
|
||||||
/**
|
/**
|
||||||
Blocks current thread until sequence terminates.
|
Blocks current thread until sequence terminates.
|
||||||
|
|
||||||
If sequence terminates with error, terminating error will be thrown.
|
If sequence terminates with error, terminating error will be thrown.
|
||||||
|
|
||||||
- returns: Last element in the sequence. If sequence is empty `nil` is returned.
|
- returns: Last element in the sequence. If sequence is empty `nil` is returned.
|
||||||
*/
|
*/
|
||||||
public func last() throws -> E? {
|
public func last() throws -> E? {
|
||||||
let condition = NSCondition()
|
|
||||||
|
|
||||||
var element: E?
|
var element: E?
|
||||||
|
|
||||||
var error: ErrorType?
|
var error: ErrorType?
|
||||||
|
|
||||||
var ended = false
|
|
||||||
|
|
||||||
let d = SingleAssignmentDisposable()
|
let d = SingleAssignmentDisposable()
|
||||||
|
|
||||||
d.disposable = self.source.subscribe { e in
|
let lock = RunLoopLock()
|
||||||
switch e {
|
|
||||||
case .Next(let e):
|
lock.dispatch {
|
||||||
element = e
|
d.disposable = self.source.subscribe { e in
|
||||||
return
|
switch e {
|
||||||
case .Error(let e):
|
case .Next(let e):
|
||||||
error = e
|
element = e
|
||||||
default:
|
return
|
||||||
break
|
case .Error(let e):
|
||||||
|
error = e
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
condition.lock()
|
|
||||||
ended = true
|
|
||||||
condition.signal()
|
|
||||||
condition.unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
condition.lock()
|
lock.run()
|
||||||
while !ended {
|
|
||||||
condition.wait()
|
|
||||||
}
|
|
||||||
d.dispose()
|
d.dispose()
|
||||||
condition.unlock()
|
|
||||||
|
|
||||||
if let error = error {
|
if let error = error {
|
||||||
throw error
|
throw error
|
||||||
|
33
RxBlocking/RunLoopLock.swift
Normal file
33
RxBlocking/RunLoopLock.swift
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// RunLoopLock.swift
|
||||||
|
// Rx
|
||||||
|
//
|
||||||
|
// Created by Krunoslav Zaher on 11/5/15.
|
||||||
|
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class RunLoopLock : NSObject {
|
||||||
|
let currentRunLoop: CFRunLoopRef
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
currentRunLoop = CFRunLoopGetCurrent()
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatch(action: () -> ()) {
|
||||||
|
CFRunLoopPerformBlock(currentRunLoop, kCFRunLoopDefaultMode, action)
|
||||||
|
CFRunLoopWakeUp(currentRunLoop)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
CFRunLoopPerformBlock(currentRunLoop, kCFRunLoopDefaultMode) {
|
||||||
|
CFRunLoopStop(self.currentRunLoop)
|
||||||
|
}
|
||||||
|
CFRunLoopWakeUp(currentRunLoop)
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() {
|
||||||
|
CFRunLoopRun()
|
||||||
|
}
|
||||||
|
}
|
@ -30,8 +30,8 @@ extension ObservableBlockingTest {
|
|||||||
try (failWith(testError) as Observable<Int>).toBlocking().toArray()
|
try (failWith(testError) as Observable<Int>).toBlocking().toArray()
|
||||||
XCTFail("It should fail")
|
XCTFail("It should fail")
|
||||||
}
|
}
|
||||||
catch {
|
catch let e {
|
||||||
|
XCTAssertTrue(e as NSError === testError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +67,8 @@ extension ObservableBlockingTest {
|
|||||||
try (failWith(testError) as Observable<Int>).toBlocking().first()
|
try (failWith(testError) as Observable<Int>).toBlocking().first()
|
||||||
XCTFail()
|
XCTFail()
|
||||||
}
|
}
|
||||||
catch {
|
catch let e {
|
||||||
|
XCTAssertTrue(e as NSError === testError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,8 +104,8 @@ extension ObservableBlockingTest {
|
|||||||
try (failWith(testError) as Observable<Int>).toBlocking().last()
|
try (failWith(testError) as Observable<Int>).toBlocking().last()
|
||||||
XCTFail()
|
XCTFail()
|
||||||
}
|
}
|
||||||
catch {
|
catch let e {
|
||||||
|
XCTAssertTrue(e as NSError === testError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user