diff --git a/Documentation/API.md b/Documentation/API.md index 32651338..74d11aae 100644 --- a/Documentation/API.md +++ b/Documentation/API.md @@ -455,3 +455,11 @@ extension NSTextField { } ``` + +```swift +extension UITabBarItem { + + public var rx_badgeValue: AnyObserver {} + +} +``` diff --git a/Documentation/Examples.md b/Documentation/Examples.md index ae81a65b..78950266 100644 --- a/Documentation/Examples.md +++ b/Documentation/Examples.md @@ -46,7 +46,9 @@ let b /*: Observable*/ = Variable(2) // b = 2 // if a + b >= 0 { // c = "\(a + b) is positive" // } -let c = Observable.combineLatest(a, b) { $0 + $1 } // combines latest values of variables `a` and `b` using `+` + + // combines latest values of variables `a` and `b` using `+` +let c = Observable.combineLatest(a.asObservable(), b.asObservable()) { $0 + $1 } .filter { $0 >= 0 } // if `a + b >= 0` is true, `a + b` is passed to map operator .map { "\($0) is positive" } // maps `a + b` to "\(a + b) is positive" diff --git a/Documentation/GettingStarted.md b/Documentation/GettingStarted.md index 0abc561a..91856923 100644 --- a/Documentation/GettingStarted.md +++ b/Documentation/GettingStarted.md @@ -481,7 +481,7 @@ Disposed Ended ---- ``` -**Every subscriber upon subscription usually generates it's own separate sequence of elements. Operators are stateless by default. There is vastly more stateless operators then stateful ones.** +**Every subscriber upon subscription usually generates it's own separate sequence of elements. Operators are stateless by default. There are vastly more stateless operators than stateful ones.** ## Sharing subscription and `shareReplay` operator @@ -771,7 +771,7 @@ Usually after you have fixed the error, you can remove the type annotations to c ## Debugging -Using debugger alone is useful, but you can also use `debug`. `debug` operator will print out all events to standard output and you can add also label those events. +Using debugger alone is useful, but usually using `debug` operator will be more efficient. `debug` operator will print out all events to standard output and you can add also label those events. `debug` acts like a probe. Here is an example of using it: @@ -809,17 +809,34 @@ This is simply 4 Disposed ``` -You can also use `subscribe` instead of `subscribeNext` +You can also easily create your version of the `debug` operator. ```swift -NSURLSession.sharedSession().rx_JSON(request) - .map { json in - return parse() - } - .subscribe { n in // this subscribes on all events including error and completed - print(n) - } -``` +extension ObservableType { + public func myDebug(identifier: String) -> Observable { + return Observable.create { observer in + print("subscribed \(identifier)") + let subscription = self.subscribe { e in + print("event \(identifier) \(e)") + switch e { + case .Next(let value): + observer.on(.Next(value)) + + case .Error(let error): + observer.on(.Error(error)) + + case .Completed: + observer.on(.Completed) + } + } + return AnonymousDisposable { + print("disposing \(identifier)") + subscription.dispose() + } + } + } + } + ``` ## Debugging memory leaks @@ -964,7 +981,7 @@ self.rx_observe(CGRect.self, "view.frame", retainSelf: false) ### `rx_observeWeakly` -`rx_observeWeakly` has somewhat slower then `rx_observe` because it has to handle object deallocation in case of weak references. +`rx_observeWeakly` has somewhat slower than `rx_observe` because it has to handle object deallocation in case of weak references. It can be used in all cases where `rx_observe` can be used and additionally diff --git a/Documentation/Tips.md b/Documentation/Tips.md new file mode 100644 index 00000000..927687a8 --- /dev/null +++ b/Documentation/Tips.md @@ -0,0 +1,50 @@ +Tips +==== + +* Always strive to model your systems or their parts as pure functions. Those pure functions can be tested easily and can be used to modify operator behaviors. +* When you are using Rx, first try to compose built-in operators. +* If using some combination of operators often, create your convenience operators. + +e.g. +```swift +extension ObservableType where E: MaybeCool { + + @warn_unused_result(message="http://git.io/rxs.uo") + public func coolElements() + -> Observable { + return filter { e -> Bool in + return e.isCool + } + } +} +``` + + * Rx operators are as general as possible, but there will always be edge cases that will be hard to model. In those cases you can just create your own operator and possibly use one of the built-in operators as a reference. + + * Always use operators to compose subscriptions. + + **Avoid nesting subscribe calls at all cost. This is a bad smell.** + + ```swift + textField.rx_text.subscribeNext { text in + performURLRequest(text).subscribeNext { result in + ... + } + .addDisposableTo(disposeBag) + } + .addDisposableTo(disposeBag) + ``` + + **Preferred way of chaining disposables by using operators.** + + ```swift + textField.rx_text + .flatMapLatest { text in + // Assuming this doesn't fail and returns result on main scheduler, + // otherwise `catchError` and `observeOn(MainScheduler.instance)` can be used to + // correct this. + return performURLRequest(text) + } + ... + .addDisposableTo(disposeBag) // only one top most disposable + ``` diff --git a/Documentation/UnitTests.md b/Documentation/UnitTests.md new file mode 100644 index 00000000..3d1ec8ac --- /dev/null +++ b/Documentation/UnitTests.md @@ -0,0 +1,97 @@ +Unit Tests +========== + +## Testing custom operators + +Library uses `RxTests` for all of RxSwift operator tests so you can take a look at AllTests-* target inside the project `Rx.xcworkspace`. + +This is an example of a typical `RxSwift` operator unit test: + +```swift +func testMap_Range() { + // Initializes test scheduler. + // Test scheduler implements virtual time that is + // detached from local machine clock. + // That enables running the simulation as fast as possible + // and proving that all events have been handled. + let scheduler = TestScheduler(initialClock: 0) + + // Creates a mock hot observable sequence. + // The sequence will emit events at following + // times no matter is there some observer subscribed. + // (that's what hot means). + // This observable sequence will also record all subscriptions + // made during it's lifetime (`subscriptions` property). + let xs = scheduler.createHotObservable([ + next(150, 1), // first argument is virtual time, second argument is element value + next(210, 0), + next(220, 1), + next(230, 2), + next(240, 4), + completed(300) // virtual time when completed is sent + ]) + + // `start` method will by default: + // * run the simulation and record all events + // using observer referenced by `res`. + // * subscribe at virtual time 200 + // * dispose subscription at virtual time 1000 + let res = scheduler.start { xs.map { $0 * 2 } } + + let correctMessages = [ + next(210, 0 * 2), + next(220, 1 * 2), + next(230, 2 * 2), + next(240, 4 * 2), + completed(300) + ] + + let correctSubscriptions = [ + Subscription(200, 300) + ] + + XCTAssertEqual(res.events, correctMessages) + XCTAssertEqual(xs.subscriptions, correctSubscriptions) + } +``` + +## Testing operator compositions (view models, components) + +Examples how to test operator compositions are contained inside `Rx.xcworkspace` > `RxExample-iOSTests` target. + +It easy to define `RxTests` extensions so you can write your tests in a readable way. Provided examples inside `RxExample-iOSTests` are just a tip how you can write those extensions, but there is a lot of possibilities how to write those tests. + +```swift + // expected events and test data + let ( + usernameEvents, + passwordEvents, + repeatedPasswordEvents, + loginTapEvents, + + expectedValidatedUsernameEvents, + expectedSignupEnabledEvents + ) = ( + scheduler.parseEventsAndTimes("e---u1----u2-----u3-----------------", values: stringValues).first!, + scheduler.parseEventsAndTimes("e----------------------p1-----------", values: stringValues).first!, + scheduler.parseEventsAndTimes("e---------------------------p2---p1-", values: stringValues).first!, + scheduler.parseEventsAndTimes("------------------------------------", values: events).first!, + + scheduler.parseEventsAndTimes("e---v--f--v--f---v--o----------------", values: validations).first!, + scheduler.parseEventsAndTimes("f--------------------------------t---", values: booleans).first! + ) +``` + +## Integration tests + +It is also possible to write integration tests by using `RxBlocking` operators. + +Importing operators from `RxBlocking` library will enable blocking the current thread and wait for sequence results. + +```swift +let result = try fetchResource(location) + .toBlocking() + .toArray() + +XCTAssertEqual(result, expectedResult) +``` diff --git a/README.md b/README.md index cdb4b7c0..7fa679cc 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,11 @@ KVO observing, async operations and streams are all unified under [abstraction o ###### ... understand * [why use rx?](Documentation/Why.md) -* how does RxSwift work? [Getting Started Guide](Documentation/GettingStarted.md) -* what is `Driver`, `ControlProperty`, and `Variable` ... and why do they exist? [Units](Documentation/Units.md) +* [the basics, getting started with RxSwift](Documentation/GettingStarted.md) +* [units](Documentation/Units.md) - what is `Driver`, `ControlProperty`, and `Variable` ... and why do they exist? +* [testing](Documentation/UnitTests.md) +* [tips and common errors](Documentation/Tips.md) +* [debugging](Documentation/GettingStarted.md#debugging) * [the math behind Rx](Documentation/MathBehindRx.md) * [what are hot and cold observable sequences?](Documentation/HotAndColdObservables.md) * [what does the the public API look like?](Documentation/API.md) diff --git a/Rx.playground/Pages/Combining_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Combining_Observables.xcplaygroundpage/Contents.swift index 7887749b..8935a67f 100644 --- a/Rx.playground/Pages/Combining_Observables.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Combining_Observables.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/Pages/Conditional_and_Boolean_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Conditional_and_Boolean_Operators.xcplaygroundpage/Contents.swift index 9da1d2ec..d14a2cda 100644 --- a/Rx.playground/Pages/Conditional_and_Boolean_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Conditional_and_Boolean_Operators.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import Cocoa diff --git a/Rx.playground/Pages/Connectable_Observable_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Connectable_Observable_Operators.xcplaygroundpage/Contents.swift index 1bbdd93b..208caf56 100644 --- a/Rx.playground/Pages/Connectable_Observable_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Connectable_Observable_Operators.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/Pages/Error_Handling_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Error_Handling_Operators.xcplaygroundpage/Contents.swift index 71f812ca..206279e9 100644 --- a/Rx.playground/Pages/Error_Handling_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Error_Handling_Operators.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/Pages/Filtering_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Filtering_Observables.xcplaygroundpage/Contents.swift index 1f6406f1..29405905 100644 --- a/Rx.playground/Pages/Filtering_Observables.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Filtering_Observables.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift index cb6598bf..720c1a62 100644 --- a/Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift @@ -1,6 +1,6 @@ /*: -> # IMPORTANT: To use `RxSamples`, please: +> # IMPORTANT: To use `Rx.playground`, please: 1. Open `Rx.xcworkspace` 2. Build `RxSwift-OSX` scheme diff --git a/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift index 81be41fa..04994d5a 100644 --- a/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Index](@previous) import RxSwift diff --git a/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift index 9e390081..a6b78f35 100644 --- a/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/Pages/Observable_Utility_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Observable_Utility_Operators.xcplaygroundpage/Contents.swift index 3010400c..a1230154 100644 --- a/Rx.playground/Pages/Observable_Utility_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Observable_Utility_Operators.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift index e74015e4..dc8df166 100644 --- a/Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift index f0216cf5..57f978b5 100644 --- a/Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift @@ -1,3 +1,12 @@ +/*: +> # IMPORTANT: To use `Rx.playground`, please: + +1. Open `Rx.xcworkspace` +2. Build `RxSwift-OSX` scheme +3. And then open `Rx` playground in `Rx.xcworkspace` tree view. +4. Choose `View > Show Debug Area` +*/ + //: [<< Previous](@previous) - [Index](Index) import RxSwift diff --git a/Rx.playground/contents.xcplayground b/Rx.playground/contents.xcplayground index 0d291cc1..f511ccd7 100644 --- a/Rx.playground/contents.xcplayground +++ b/Rx.playground/contents.xcplayground @@ -1,5 +1,5 @@ - + diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index 594d9c37..d46fc555 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -11,6 +11,11 @@ 79E9DE8A1C3417FD009970AF /* DispatchQueueSchedulerQOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79E9DE881C3417FD009970AF /* DispatchQueueSchedulerQOS.swift */; }; 79E9DE8B1C3417FD009970AF /* DispatchQueueSchedulerQOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79E9DE881C3417FD009970AF /* DispatchQueueSchedulerQOS.swift */; }; 79E9DE8C1C3417FD009970AF /* DispatchQueueSchedulerQOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79E9DE881C3417FD009970AF /* DispatchQueueSchedulerQOS.swift */; }; + 7EDBAEB41C89B1A6006CBE67 /* UITabBarItem+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EDBAEAB1C89B1A5006CBE67 /* UITabBarItem+RxTests.swift */; }; + 7EDBAEBC1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EDBAEB71C89B9B7006CBE67 /* UITabBarItem+Rx.swift */; }; + 7EDBAEBE1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EDBAEB71C89B9B7006CBE67 /* UITabBarItem+Rx.swift */; }; + 7EDBAEBF1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EDBAEB71C89B9B7006CBE67 /* UITabBarItem+Rx.swift */; }; + 7EDBAEC31C89BCB9006CBE67 /* UITabBarItem+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EDBAEAB1C89B1A5006CBE67 /* UITabBarItem+RxTests.swift */; }; 7F600F3F1C5D0C6C00535B1D /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F600F3D1C5D0C0100535B1D /* UIRefreshControl+Rx.swift */; }; 7F600F401C5D0C6D00535B1D /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F600F3D1C5D0C0100535B1D /* UIRefreshControl+Rx.swift */; }; 7F600F411C5D0C6E00535B1D /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F600F3D1C5D0C0100535B1D /* UIRefreshControl+Rx.swift */; }; @@ -35,6 +40,8 @@ 9BA1CBFD1C0F84A10044B50A /* UIActivityIndicatorView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BA1CBD11C0F7C0A0044B50A /* UIActivityIndicatorView+Rx.swift */; }; 9BA1CBFE1C0F84C40044B50A /* UIActivityIndicatorView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BA1CBD11C0F7C0A0044B50A /* UIActivityIndicatorView+Rx.swift */; }; 9D71C4D21BF08191006E8F59 /* UIButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254061B8A752B00B02D69 /* UIButton+Rx.swift */; }; + AAE623761C82475700FC7801 /* UIProgressView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE623751C82475700FC7801 /* UIProgressView+Rx.swift */; }; + AAE623771C82475700FC7801 /* UIProgressView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE623751C82475700FC7801 /* UIProgressView+Rx.swift */; }; B1B7C3BD1BDD39DB0076934E /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B7C3BC1BDD39DB0076934E /* TakeLast.swift */; }; B1B7C3BE1BDD39DB0076934E /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B7C3BC1BDD39DB0076934E /* TakeLast.swift */; }; B1B7C3BF1BDD39DB0076934E /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B7C3BC1BDD39DB0076934E /* TakeLast.swift */; }; @@ -635,6 +642,10 @@ C8B145011BD2D80100267DCE /* ImmediateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */; }; C8B145021BD2D80100267DCE /* ImmediateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */; }; C8B145031BD2D80100267DCE /* ImmediateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */; }; + C8B290891C94D64600E923D0 /* RxTest+Controls.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B290841C94D55600E923D0 /* RxTest+Controls.swift */; }; + C8B2908A1C94D64700E923D0 /* RxTest+Controls.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B290841C94D55600E923D0 /* RxTest+Controls.swift */; }; + C8B2908B1C94D64700E923D0 /* RxTest+Controls.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B290841C94D55600E923D0 /* RxTest+Controls.swift */; }; + C8B2908D1C94D6C500E923D0 /* UISearchBar+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B2908C1C94D6C500E923D0 /* UISearchBar+RxTests.swift */; }; C8BCD3C71C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */; }; C8BCD3C81C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */; }; C8BCD3C91C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */; }; @@ -1316,6 +1327,8 @@ /* Begin PBXFileReference section */ 79E9DE881C3417FD009970AF /* DispatchQueueSchedulerQOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchQueueSchedulerQOS.swift; sourceTree = ""; }; + 7EDBAEAB1C89B1A5006CBE67 /* UITabBarItem+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITabBarItem+RxTests.swift"; sourceTree = ""; }; + 7EDBAEB71C89B9B7006CBE67 /* UITabBarItem+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITabBarItem+Rx.swift"; sourceTree = ""; }; 7F600F3D1C5D0C0100535B1D /* UIRefreshControl+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+Rx.swift"; sourceTree = ""; }; 7F600F421C5D0D2D00535B1D /* UIRefreshControl+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+RxTests.swift"; sourceTree = ""; }; 842A5A281C357F7D003568D5 /* NSTextStorage+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTextStorage+Rx.swift"; sourceTree = ""; }; @@ -1325,6 +1338,7 @@ 84C225A21C33F00B008724EC /* RxTextStorageDelegateProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxTextStorageDelegateProxy.swift; sourceTree = ""; }; 9BA1CBD11C0F7C0A0044B50A /* UIActivityIndicatorView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+Rx.swift"; sourceTree = ""; }; A111CE961B91C97C00D0DCEE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AAE623751C82475700FC7801 /* UIProgressView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIProgressView+Rx.swift"; sourceTree = ""; }; B1B7C3BC1BDD39DB0076934E /* TakeLast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TakeLast.swift; sourceTree = ""; }; B1D8998E1BF653410027B05C /* Timeout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timeout.swift; sourceTree = ""; }; C807F3611C2ACED300017910 /* TestSchedulerVirtualTimeConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSchedulerVirtualTimeConverter.swift; sourceTree = ""; }; @@ -1603,6 +1617,8 @@ C8A56AD71AD7424700B4673B /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C8B144FA1BD2D44500267DCE /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentMainScheduler.swift; sourceTree = ""; }; C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImmediateScheduler.swift; sourceTree = ""; }; + C8B290841C94D55600E923D0 /* RxTest+Controls.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RxTest+Controls.swift"; sourceTree = ""; }; + C8B2908C1C94D6C500E923D0 /* UISearchBar+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UISearchBar+RxTests.swift"; sourceTree = ""; }; C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareReplay1WhileConnected.swift; sourceTree = ""; }; C8BCD3EC1C14B5FB005F1280 /* UIView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Rx.swift"; sourceTree = ""; }; C8BCD3F11C14B62B005F1280 /* NSView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSView+Rx.swift"; sourceTree = ""; }; @@ -2175,6 +2191,7 @@ C8D132511C42DA7F00B59FFF /* TestImplementations */, C83508D91C38706D0027C24C /* CLLocationManager+RxTests.swift */, 8476A01F1C3D5D580040BA22 /* UIImagePickerController+RxTests.swift */, + C8B290841C94D55600E923D0 /* RxTest+Controls.swift */, C83508DA1C38706D0027C24C /* Control+RxTests+Cocoa.swift */, C83508DB1C38706D0027C24C /* Control+RxTests+UIKit.swift */, C83508DC1C38706D0027C24C /* Control+RxTests.swift */, @@ -2200,6 +2217,8 @@ C83508F01C38706D0027C24C /* SentMessageTest.swift */, C83508F11C38706D0027C24C /* UIView+RxTests.swift */, 7F600F421C5D0D2D00535B1D /* UIRefreshControl+RxTests.swift */, + 7EDBAEAB1C89B1A5006CBE67 /* UITabBarItem+RxTests.swift */, + C8B2908C1C94D6C500E923D0 /* UISearchBar+RxTests.swift */, ); path = RxCocoaTests; sourceTree = ""; @@ -2322,6 +2341,7 @@ C882540A1B8A752B00B02D69 /* UIGestureRecognizer+Rx.swift */, C882540B1B8A752B00B02D69 /* UIImageView+Rx.swift */, C882540C1B8A752B00B02D69 /* UILabel+Rx.swift */, + AAE623751C82475700FC7801 /* UIProgressView+Rx.swift */, 7F600F3D1C5D0C0100535B1D /* UIRefreshControl+Rx.swift */, C882540D1B8A752B00B02D69 /* UIScrollView+Rx.swift */, C882540E1B8A752B00B02D69 /* UISearchBar+Rx.swift */, @@ -2336,6 +2356,7 @@ 9BA1CBD11C0F7C0A0044B50A /* UIActivityIndicatorView+Rx.swift */, 8479BC4A1C3ACED100FB8B54 /* UIImagePickerController+Rx.swift */, C8BCD3EC1C14B5FB005F1280 /* UIView+Rx.swift */, + 7EDBAEB71C89B9B7006CBE67 /* UITabBarItem+Rx.swift */, ); path = iOS; sourceTree = ""; @@ -3244,6 +3265,7 @@ C882542E1B8A752B00B02D69 /* UILabel+Rx.swift in Sources */, C88254211B8A752B00B02D69 /* RxSearchBarDelegateProxy.swift in Sources */, C80DDEA71BCE69BA006A1832 /* ObservableConvertibleType+Driver.swift in Sources */, + 7EDBAEBC1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */, C839365F1C70E02200A9A09E /* UIApplication+Rx.swift in Sources */, C80DDE9F1BCE69BA006A1832 /* Driver+Subscription.swift in Sources */, C811C89D1C24D80100A2DDD4 /* DeallocObservable.swift in Sources */, @@ -3251,6 +3273,7 @@ C80D338F1B91EF9E0014629D /* Observable+Bind.swift in Sources */, C88254311B8A752B00B02D69 /* UISegmentedControl+Rx.swift in Sources */, C8093EED1B8A732E0088E94D /* KVOObservable.swift in Sources */, + AAE623761C82475700FC7801 /* UIProgressView+Rx.swift in Sources */, C8DB968D1BF7595D0084BD53 /* KVORepresentable+Swift.swift in Sources */, C80DDEB11BCE8CA3006A1832 /* Driver+Operators+arity.swift in Sources */, C88254281B8A752B00B02D69 /* UIButton+Rx.swift in Sources */, @@ -3372,6 +3395,7 @@ C835094B1C38706E0027C24C /* AnonymousObservable+Test.swift in Sources */, C835092E1C38706E0027C24C /* ControlEventTests.swift in Sources */, C83509531C38706E0027C24C /* Observable+AggregateTest.swift in Sources */, + C8B290891C94D64600E923D0 /* RxTest+Controls.swift in Sources */, C83509291C38706E0027C24C /* PerformanceTools.swift in Sources */, C835096A1C38706E0027C24C /* TestErrors.swift in Sources */, C83509561C38706E0027C24C /* Observable+ConcurrencyTest.swift in Sources */, @@ -3385,6 +3409,7 @@ C835095F1C38706E0027C24C /* Observable+SubscriptionTest.swift in Sources */, C83509451C38706E0027C24C /* Observable.Extensions.swift in Sources */, C835093B1C38706E0027C24C /* RXObjCRuntime+Testing.m in Sources */, + C8B2908D1C94D6C500E923D0 /* UISearchBar+RxTests.swift in Sources */, C83509641C38706E0027C24C /* VariableTest.swift in Sources */, C83509461C38706E0027C24C /* PrimitiveHotObservable.swift in Sources */, C835097E1C38726E0027C24C /* RxMutableBox.swift in Sources */, @@ -3396,6 +3421,7 @@ C83509331C38706E0027C24C /* Driver+Extensions.swift in Sources */, C835094F1C38706E0027C24C /* CurrentThreadSchedulerTest.swift in Sources */, C835093E1C38706E0027C24C /* UIView+RxTests.swift in Sources */, + 7EDBAEB41C89B1A6006CBE67 /* UITabBarItem+RxTests.swift in Sources */, C83509411C38706E0027C24C /* BackgroundThreadPrimitiveHotObservable.swift in Sources */, C83509581C38706E0027C24C /* Observable+MultipleTest+CombineLatest.swift in Sources */, C83509651C38706E0027C24C /* VirtualSchedulerTest.swift in Sources */, @@ -3444,6 +3470,7 @@ C83509EE1C3875580027C24C /* Observable.Extensions.swift in Sources */, C83509BD1C38750D0027C24C /* ControlPropertyTests.swift in Sources */, C83509E11C3875500027C24C /* TestVirtualScheduler.swift in Sources */, + C8B2908A1C94D64700E923D0 /* RxTest+Controls.swift in Sources */, C8350A181C38756A0027C24C /* VariableTest.swift in Sources */, C83509EF1C3875580027C24C /* PrimitiveHotObservable.swift in Sources */, C83509FB1C38755D0027C24C /* Observable+BindingTest.swift in Sources */, @@ -3481,6 +3508,7 @@ C8350A121C38756A0027C24C /* Observable+StandardSequenceOperatorsTest.swift in Sources */, C83509C31C3875220027C24C /* KVOObservableTests.swift in Sources */, C83509F91C38755D0027C24C /* MainSchedulerTests.swift in Sources */, + 7EDBAEC31C89BCB9006CBE67 /* UITabBarItem+RxTests.swift in Sources */, C83509AB1C3874D20027C24C /* XCTest+AllTests.swift in Sources */, C83509C11C3875220027C24C /* Driver+Extensions.swift in Sources */, C83509DD1C38754C0027C24C /* EquatableArray.swift in Sources */, @@ -3534,6 +3562,7 @@ C8350A081C38755E0027C24C /* Observable+AggregateTest.swift in Sources */, C83509E81C3875580027C24C /* PrimitiveMockObserver.swift in Sources */, C83509BE1C3875100027C24C /* DelegateProxyTest+Cocoa.swift in Sources */, + C8B2908B1C94D64700E923D0 /* RxTest+Controls.swift in Sources */, C8350A1B1C38756B0027C24C /* Observable+SingleTest.swift in Sources */, C8350A231C38756B0027C24C /* VirtualSchedulerTest.swift in Sources */, C83509E51C3875580027C24C /* MySubject.swift in Sources */, @@ -4173,6 +4202,7 @@ C8F0C03A1BBBFBB9001B112F /* ControlTarget.swift in Sources */, C8F0C03B1BBBFBB9001B112F /* UISearchBar+Rx.swift in Sources */, C8F0C03C1BBBFBB9001B112F /* ItemEvents.swift in Sources */, + 7EDBAEBF1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */, C8DB968B1BF756F40084BD53 /* KVORepresentable+CoreGraphics.swift in Sources */, C8FD21B11C67E14C00863EC3 /* UIBindingObserver.swift in Sources */, C8F0C03D1BBBFBB9001B112F /* RxTableViewDataSourceType.swift in Sources */, @@ -4248,6 +4278,7 @@ D203C50D1BB9C53E00D02D00 /* UISegmentedControl+Rx.swift in Sources */, C8C4B4C41C17727000828BD5 /* MessageSentObserver.swift in Sources */, D2138C861BB9BEBE00339B5C /* Observable+Bind.swift in Sources */, + AAE623771C82475700FC7801 /* UIProgressView+Rx.swift in Sources */, D203C50A1BB9C53E00D02D00 /* UILabel+Rx.swift in Sources */, D203C4F51BB9C52900D02D00 /* ItemEvents.swift in Sources */, C8BCD3F61C14B6D1005F1280 /* NSLayoutConstraint+Rx.swift in Sources */, @@ -4265,6 +4296,7 @@ 9D71C4D21BF08191006E8F59 /* UIButton+Rx.swift in Sources */, D203C4FD1BB9C53700D02D00 /* RxSearchBarDelegateProxy.swift in Sources */, D2138C8A1BB9BEBE00339B5C /* Logging.swift in Sources */, + 7EDBAEBE1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */, C8DB968A1BF756F40084BD53 /* KVORepresentable+CoreGraphics.swift in Sources */, C8FD21B01C67E14C00863EC3 /* UIBindingObserver.swift in Sources */, D203C50F1BB9C53E00D02D00 /* UIStepper+Rx.swift in Sources */, diff --git a/RxCocoa/Common/Observables/NSNotificationCenter+Rx.swift b/RxCocoa/Common/Observables/NSNotificationCenter+Rx.swift index 0f912e36..a9ad4517 100644 --- a/RxCocoa/Common/Observables/NSNotificationCenter+Rx.swift +++ b/RxCocoa/Common/Observables/NSNotificationCenter+Rx.swift @@ -20,7 +20,7 @@ extension NSNotificationCenter { - returns: Observable sequence of posted notifications. */ @warn_unused_result(message="http://git.io/rxs.uo") - public func rx_notification(name: String, object: AnyObject? = nil) -> Observable { + public func rx_notification(name: String?, object: AnyObject? = nil) -> Observable { return Observable.create { [weak object] observer in let nsObserver = self.addObserverForName(name, object: object, queue: nil) { notification in observer.on(.Next(notification)) diff --git a/RxCocoa/Common/Observables/NSURLSession+Rx.swift b/RxCocoa/Common/Observables/NSURLSession+Rx.swift index 5fef6e6d..99bceaa3 100644 --- a/RxCocoa/Common/Observables/NSURLSession+Rx.swift +++ b/RxCocoa/Common/Observables/NSURLSession+Rx.swift @@ -180,7 +180,7 @@ extension NSURLSession { public func rx_data(request: NSURLRequest) -> Observable { return rx_response(request).map { (data, response) -> NSData in if 200 ..< 300 ~= response.statusCode { - return data ?? NSData() + return data } else { throw RxCocoaURLError.HTTPRequestFailed(response: response, data: data) @@ -209,7 +209,7 @@ extension NSURLSession { public func rx_JSON(request: NSURLRequest) -> Observable { return rx_data(request).map { (data) -> AnyObject in do { - return try NSJSONSerialization.JSONObjectWithData(data ?? NSData(), options: []) + return try NSJSONSerialization.JSONObjectWithData(data, options: []) } catch let error { throw RxCocoaURLError.DeserializationError(error: error) } diff --git a/RxCocoa/Common/_RXDelegateProxy.m b/RxCocoa/Common/_RXDelegateProxy.m index 03595af6..581fbabb 100644 --- a/RxCocoa/Common/_RXDelegateProxy.m +++ b/RxCocoa/Common/_RXDelegateProxy.m @@ -41,6 +41,8 @@ static NSMutableDictionary *forwardableSelectorsPerClass = nil; for (unsigned int i = 0; i < numberOfBaseProtocols; ++i) { [selectors unionSet:[self collectSelectorsForProtocol:pSubprotocols[i]]]; } + + free(pSubprotocols); return selectors; } diff --git a/RxCocoa/iOS/UICollectionView+Rx.swift b/RxCocoa/iOS/UICollectionView+Rx.swift index 8147c6ac..4bd618f7 100644 --- a/RxCocoa/iOS/UICollectionView+Rx.swift +++ b/RxCocoa/iOS/UICollectionView+Rx.swift @@ -112,9 +112,7 @@ extension UICollectionView { For more information take a look at `DelegateProxyType` protocol documentation. */ public var rx_dataSource: DelegateProxy { - get { - return proxyForObject(RxCollectionViewDataSourceProxy.self, self) - } + return proxyForObject(RxCollectionViewDataSourceProxy.self, self) } /** diff --git a/RxCocoa/iOS/UIProgressView+Rx.swift b/RxCocoa/iOS/UIProgressView+Rx.swift new file mode 100644 index 00000000..3b59dd71 --- /dev/null +++ b/RxCocoa/iOS/UIProgressView+Rx.swift @@ -0,0 +1,30 @@ +// +// UIProgressView+Rx.swift +// Rx +// +// Created by Samuel Bae on 2/27/16. +// Copyright © 2016 Krunoslav Zaher. All rights reserved. +// + +#if os(iOS) || os(tvOS) + +import Foundation +#if !RX_NO_MODULE +import RxSwift +#endif +import UIKit + +extension UIProgressView { + + /** + Bindable sink for `progress` property + */ + public var rx_progress: AnyObserver { + return UIBindingObserver(UIElement: self) { progressView, progress in + progressView.progress = progress + }.asObserver() + } + +} + +#endif \ No newline at end of file diff --git a/RxCocoa/iOS/UITabBarItem+Rx.swift b/RxCocoa/iOS/UITabBarItem+Rx.swift new file mode 100644 index 00000000..2d07cde4 --- /dev/null +++ b/RxCocoa/iOS/UITabBarItem+Rx.swift @@ -0,0 +1,30 @@ +// +// UITabBarItem+Rx.swift +// Rx +// +// Created by Mateusz Derks on 04/03/16. +// Copyright © 2016 Krunoslav Zaher. All rights reserved. +// + +#if os(iOS) || os(tvOS) + + import Foundation + import UIKit +#if !RX_NO_MODULE + import RxSwift +#endif + +extension UITabBarItem { + + /** + Bindable sink for `badgeValue` property. + */ + public var rx_badgeValue: AnyObserver { + return UIBindingObserver(UIElement: self) { tabBarItem, badgeValue in + tabBarItem.badgeValue = badgeValue + }.asObserver() + } + +} + +#endif diff --git a/RxCocoa/iOS/UITextView+Rx.swift b/RxCocoa/iOS/UITextView+Rx.swift index f21d31a9..06389f3a 100644 --- a/RxCocoa/iOS/UITextView+Rx.swift +++ b/RxCocoa/iOS/UITextView+Rx.swift @@ -35,7 +35,14 @@ extension UITextView { let text = self?.text ?? "" let textChanged = self?.textStorage + // This project uses text storage notifications because + // that's the only way to catch autocorrect changes + // in all cases. Other suggestions are welcome. .rx_didProcessEditingRangeChangeInLength + // This observe on is here because text storage + // will emit event while process is not completely done, + // so rebinding a value will cause an exception to be thrown. + .observeOn(MainScheduler.asyncInstance) .map { _ in return self?.textStorage.string ?? "" } diff --git a/RxExample/RxDataSourceStarterKit/Changeset.swift b/RxExample/RxDataSourceStarterKit/Changeset.swift index 39989fa3..3673182d 100644 --- a/RxExample/RxDataSourceStarterKit/Changeset.swift +++ b/RxExample/RxDataSourceStarterKit/Changeset.swift @@ -18,9 +18,7 @@ struct ItemPath : CustomDebugStringConvertible { let itemIndex: Int var debugDescription : String { - get { - return "(\(sectionIndex), \(itemIndex))" - } + return "(\(sectionIndex), \(itemIndex))" } } @@ -51,20 +49,18 @@ public struct Changeset : CustomDebugStringConvertible { } public var debugDescription : String { - get { - let serializedSections = "[\n" + finalSections.map { "\($0)" }.joinWithSeparator(",\n") + "\n]\n" - return " >> Final sections" + let serializedSections = "[\n" + finalSections.map { "\($0)" }.joinWithSeparator(",\n") + "\n]\n" + return " >> Final sections" + " \n\(serializedSections)" + (insertedSections.count > 0 || deletedSections.count > 0 || movedSections.count > 0 || updatedSections.count > 0 ? "\nSections:" : "") + (insertedSections.count > 0 ? "\ninsertedSections:\n\t\(insertedSections)" : "") + (deletedSections.count > 0 ? "\ndeletedSections:\n\t\(deletedSections)" : "") + (movedSections.count > 0 ? "\nmovedSections:\n\t\(movedSections)" : "") + (updatedSections.count > 0 ? "\nupdatesSections:\n\t\(updatedSections)" : "") - + (insertedItems.count > 0 || deletedItems.count > 0 || movedItems.count > 0 || updatedItems.count > 0 ? "\nItems:" : "") + + (insertedItems.count > 0 || deletedItems.count > 0 || movedItems.count > 0 || updatedItems.count > 0 ? "\nItems:" : "") + (insertedItems.count > 0 ? "\ninsertedItems:\n\t\(insertedItems)" : "") + (deletedItems.count > 0 ? "\ndeletedItems:\n\t\(deletedItems)" : "") + (movedItems.count > 0 ? "\nmovedItems:\n\t\(movedItems)" : "") + (updatedItems.count > 0 ? "\nupdatedItems:\n\t\(updatedItems)" : "") - } } } diff --git a/RxExample/RxDataSourceStarterKit/Differentiator.swift b/RxExample/RxDataSourceStarterKit/Differentiator.swift index 24a775dd..51154ce7 100644 --- a/RxExample/RxDataSourceStarterKit/Differentiator.swift +++ b/RxExample/RxDataSourceStarterKit/Differentiator.swift @@ -33,19 +33,17 @@ enum EditEvent : CustomDebugStringConvertible { extension EditEvent { var debugDescription: String { - get { - switch self { - case .Inserted: - return "Inserted" - case .Deleted: - return "Deleted" - case .Moved: - return "Moved" - case .MovedAutomatically: - return "MovedAutomatically" - case .Untouched: - return "Untouched" - } + switch self { + case .Inserted: + return "Inserted" + case .Deleted: + return "Deleted" + case .Moved: + return "Moved" + case .MovedAutomatically: + return "MovedAutomatically" + case .Untouched: + return "Untouched" } } } @@ -57,9 +55,7 @@ struct SectionAdditionalInfo : CustomDebugStringConvertible { extension SectionAdditionalInfo { var debugDescription: String { - get { - return "\(event), \(indexAfterDelete)" - } + return "\(event), \(indexAfterDelete)" } } @@ -70,9 +66,7 @@ struct ItemAdditionalInfo : CustomDebugStringConvertible { extension ItemAdditionalInfo { var debugDescription: String { - get { - return "\(event) \(indexAfterDelete)" - } + return "\(event) \(indexAfterDelete)" } } diff --git a/RxExample/RxDataSourceStarterKit/SectionModel.swift b/RxExample/RxDataSourceStarterKit/SectionModel.swift index 2a645fb6..3a6ead4b 100644 --- a/RxExample/RxDataSourceStarterKit/SectionModel.swift +++ b/RxExample/RxDataSourceStarterKit/SectionModel.swift @@ -25,9 +25,7 @@ public struct SectionModel : SectionModelType, CustomStringCo } public var description: String { - get { - return "\(self.model) > \(items)" - } + return "\(self.model) > \(items)" } } @@ -48,15 +46,11 @@ public struct HashableSectionModel : Hash } public var description: String { - get { - return "HashableSectionModel(model: \"\(self.model)\", items: \(items))" - } + return "HashableSectionModel(model: \"\(self.model)\", items: \(items))" } public var hashValue: Int { - get { - return self.model.hashValue - } + return self.model.hashValue } } diff --git a/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift b/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift index b7a18c60..475f42f0 100644 --- a/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift +++ b/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift @@ -70,7 +70,11 @@ class APIWrappersViewController: ViewController { // MARK: UISegmentedControl - segmentedControl.rx_value + // also test two way binding + let segmentedValue = Variable(0) + segmentedControl.rx_value <-> segmentedValue + + segmentedValue.asObservable() .subscribeNext { [weak self] x in self?.debug("UISegmentedControl value \(x)") } @@ -79,7 +83,11 @@ class APIWrappersViewController: ViewController { // MARK: UISwitch - switcher.rx_value + // also test two way binding + let switchValue = Variable(false) + switcher.rx_value <-> switchValue + + switchValue.asObservable() .subscribeNext { [weak self] x in self?.debug("UISwitch value \(x)") } @@ -103,7 +111,11 @@ class APIWrappersViewController: ViewController { // MARK: UISlider - slider.rx_value + // also test two way binding + let sliderValue = Variable(0.0) + slider.rx_value <-> sliderValue + + sliderValue.asObservable() .subscribeNext { [weak self] x in self?.debug("UISlider value \(x)") } @@ -112,7 +124,12 @@ class APIWrappersViewController: ViewController { // MARK: UIDatePicker - datePicker.rx_date + // also test two way binding + let dateValue = Variable(NSDate()) + datePicker.rx_date <-> dateValue + + + dateValue.asObservable() .subscribeNext { [weak self] x in self?.debug("UIDatePicker date \(x)") } @@ -121,7 +138,11 @@ class APIWrappersViewController: ViewController { // MARK: UITextField - textField.rx_text + // also test two way binding + let textValue = Variable("") + textField.rx_text <-> textValue + + textValue.asObservable() .subscribeNext { [weak self] x in self?.debug("UITextField text \(x)") } @@ -139,7 +160,11 @@ class APIWrappersViewController: ViewController { // MARK: UITextView - textView.rx_text + // also test two way binding + let textViewValue = Variable("") + textView.rx_text <-> textViewValue + + textViewValue.asObservable() .subscribeNext { [weak self] x in self?.debug("UITextView event \(x)") } diff --git a/RxExample/RxExample/Examples/GeolocationExample/GeolocationViewController.swift b/RxExample/RxExample/Examples/GeolocationExample/GeolocationViewController.swift index e94c6c1b..06d0189e 100644 --- a/RxExample/RxExample/Examples/GeolocationExample/GeolocationViewController.swift +++ b/RxExample/RxExample/Examples/GeolocationExample/GeolocationViewController.swift @@ -23,14 +23,14 @@ private extension UILabel { private extension UIView { var rx_driveAuthorization: AnyObserver { - return UIBindingObserver(UIElement: self) { label, authorized in + return UIBindingObserver(UIElement: self) { view, authorized in if authorized { - label.hidden = true - label.superview?.sendSubviewToBack(label) + view.hidden = true + view.superview?.sendSubviewToBack(view) } else { - label.hidden = false - label.superview?.bringSubviewToFront(label) + view.hidden = false + view.superview?.bringSubviewToFront(view) } }.asObserver() } @@ -48,7 +48,6 @@ class GeolocationViewController: ViewController { let geolocationService = GeolocationService.instance - geolocationService.autorized .drive(noGeolocationView.rx_driveAuthorization) .addDisposableTo(disposeBag) diff --git a/RxExample/RxExample/Examples/ImagePicker/ImagePickerController.swift b/RxExample/RxExample/Examples/ImagePicker/ImagePickerController.swift index 3dd568d2..0f247051 100644 --- a/RxExample/RxExample/Examples/ImagePicker/ImagePickerController.swift +++ b/RxExample/RxExample/Examples/ImagePicker/ImagePickerController.swift @@ -68,7 +68,7 @@ class ImagePickerController: ViewController { .take(1) } .map { info in - return info[UIImagePickerControllerOriginalImage] as? UIImage + return info[UIImagePickerControllerEditedImage] as? UIImage } .bindTo(imageView.rx_image) .addDisposableTo(disposeBag) diff --git a/RxExample/RxExample/Examples/TableViewWithEditingCommands/User.swift b/RxExample/RxExample/Examples/TableViewWithEditingCommands/User.swift index 239ea9b5..ec5842fa 100755 --- a/RxExample/RxExample/Examples/TableViewWithEditingCommands/User.swift +++ b/RxExample/RxExample/Examples/TableViewWithEditingCommands/User.swift @@ -23,9 +23,7 @@ struct User: Equatable, CustomDebugStringConvertible { extension User { var debugDescription: String { - get { - return firstName + " " + lastName - } + return firstName + " " + lastName } } diff --git a/RxExample/RxExample/Services/ReachabilityService.swift b/RxExample/RxExample/Services/ReachabilityService.swift index 8419f4cd..fe51c95f 100644 --- a/RxExample/RxExample/Services/ReachabilityService.swift +++ b/RxExample/RxExample/Services/ReachabilityService.swift @@ -20,9 +20,7 @@ class ReachabilityService { private let _reachabilityChangedSubject = PublishSubject() private var reachabilityChanged: Observable { - get { - return _reachabilityChangedSubject.asObservable() - } + return _reachabilityChangedSubject.asObservable() } // singleton diff --git a/RxSwift/DataStructures/Bag.swift b/RxSwift/DataStructures/Bag.swift index 8b5f739c..fe074dec 100644 --- a/RxSwift/DataStructures/Bag.swift +++ b/RxSwift/DataStructures/Bag.swift @@ -35,13 +35,11 @@ public struct BagKey : Hashable { let key: Int public var hashValue: Int { - get { - if let uniqueIdentity = uniqueIdentity { - return hash(key) ^ (unsafeAddressOf(uniqueIdentity).hashValue) - } - else { - return hash(key) - } + if let uniqueIdentity = uniqueIdentity { + return hash(key) ^ (unsafeAddressOf(uniqueIdentity).hashValue) + } + else { + return hash(key) } } } @@ -212,9 +210,7 @@ extension Bag { A textual representation of `self`, suitable for debugging. */ public var debugDescription : String { - get { - return "\(self.count) elements in Bag" - } + return "\(self.count) elements in Bag" } } diff --git a/RxSwift/DataStructures/Queue.swift b/RxSwift/DataStructures/Queue.swift index 010ed9be..3b97b5f0 100644 --- a/RxSwift/DataStructures/Queue.swift +++ b/RxSwift/DataStructures/Queue.swift @@ -49,28 +49,22 @@ public struct Queue: SequenceType { } private var dequeueIndex: Int { - get { - let index = _pushNextIndex - count - return index < 0 ? index + _storage.count : index - } + let index = _pushNextIndex - count + return index < 0 ? index + _storage.count : index } /** - returns: Is queue empty. */ public var isEmpty: Bool { - get { - return count == 0 - } + return count == 0 } /** - returns: Number of elements inside queue. */ public var count: Int { - get { - return _count - } + return _count } /** diff --git a/RxSwift/Disposables/AnonymousDisposable.swift b/RxSwift/Disposables/AnonymousDisposable.swift index ee78c141..17a40910 100644 --- a/RxSwift/Disposables/AnonymousDisposable.swift +++ b/RxSwift/Disposables/AnonymousDisposable.swift @@ -23,9 +23,7 @@ public final class AnonymousDisposable : DisposeBase, Cancelable { - returns: Was resource disposed. */ public var disposed: Bool { - get { - return _disposed == 1 - } + return _disposed == 1 } /** diff --git a/RxSwift/Disposables/BinaryDisposable.swift b/RxSwift/Disposables/BinaryDisposable.swift index d2330ecb..b6176592 100644 --- a/RxSwift/Disposables/BinaryDisposable.swift +++ b/RxSwift/Disposables/BinaryDisposable.swift @@ -23,9 +23,7 @@ public final class BinaryDisposable : DisposeBase, Cancelable { - returns: Was resource disposed. */ public var disposed: Bool { - get { - return _disposed > 0 - } + return _disposed > 0 } /** diff --git a/RxSwift/Disposables/BooleanDisposable.swift b/RxSwift/Disposables/BooleanDisposable.swift index a1382155..05b8a43d 100644 --- a/RxSwift/Disposables/BooleanDisposable.swift +++ b/RxSwift/Disposables/BooleanDisposable.swift @@ -33,9 +33,7 @@ public class BooleanDisposable : Disposable, Cancelable { - returns: Was resource disposed. */ public var disposed: Bool { - get { - return _disposed - } + return _disposed } /** diff --git a/RxSwift/Disposables/CompositeDisposable.swift b/RxSwift/Disposables/CompositeDisposable.swift index 2ebf8f38..dbf50681 100644 --- a/RxSwift/Disposables/CompositeDisposable.swift +++ b/RxSwift/Disposables/CompositeDisposable.swift @@ -20,10 +20,8 @@ public class CompositeDisposable : DisposeBase, Disposable, Cancelable { private var _disposables: Bag? = Bag() public var disposed: Bool { - get { - _lock.lock(); defer { _lock.unlock() } - return _disposables == nil - } + _lock.lock(); defer { _lock.unlock() } + return _disposables == nil } public override init() { @@ -82,10 +80,8 @@ public class CompositeDisposable : DisposeBase, Disposable, Cancelable { - returns: Gets the number of disposables contained in the `CompositeDisposable`. */ public var count: Int { - get { - _lock.lock(); defer { _lock.unlock() } - return _disposables?.count ?? 0 - } + _lock.lock(); defer { _lock.unlock() } + return _disposables?.count ?? 0 } /** diff --git a/RxSwift/Disposables/RefCountDisposable.swift b/RxSwift/Disposables/RefCountDisposable.swift index 2bd13175..2d29d74a 100644 --- a/RxSwift/Disposables/RefCountDisposable.swift +++ b/RxSwift/Disposables/RefCountDisposable.swift @@ -21,10 +21,8 @@ public class RefCountDisposable : DisposeBase, Cancelable { - returns: Was resource disposed. */ public var disposed: Bool { - get { - _lock.lock(); defer { _lock.unlock() } - return _disposable == nil - } + _lock.lock(); defer { _lock.unlock() } + return _disposable == nil } /** diff --git a/RxSwift/Disposables/ScheduledDisposable.swift b/RxSwift/Disposables/ScheduledDisposable.swift index 1a1b0cd7..03c7e695 100644 --- a/RxSwift/Disposables/ScheduledDisposable.swift +++ b/RxSwift/Disposables/ScheduledDisposable.swift @@ -28,9 +28,7 @@ public class ScheduledDisposable : Cancelable { - returns: Was resource disposed. */ public var disposed: Bool { - get { - return _disposed == 1 - } + return _disposed == 1 } /** diff --git a/RxSwift/Disposables/SerialDisposable.swift b/RxSwift/Disposables/SerialDisposable.swift index 4371fdca..cb5c4e31 100644 --- a/RxSwift/Disposables/SerialDisposable.swift +++ b/RxSwift/Disposables/SerialDisposable.swift @@ -22,9 +22,7 @@ public class SerialDisposable : DisposeBase, Cancelable { - returns: Was resource disposed. */ public var disposed: Bool { - get { - return _disposed - } + return _disposed } /** diff --git a/RxSwift/Disposables/SingleAssignmentDisposable.swift b/RxSwift/Disposables/SingleAssignmentDisposable.swift index 51d4c560..a3389c11 100644 --- a/RxSwift/Disposables/SingleAssignmentDisposable.swift +++ b/RxSwift/Disposables/SingleAssignmentDisposable.swift @@ -25,9 +25,7 @@ public class SingleAssignmentDisposable : DisposeBase, Disposable, Cancelable { - returns: A value that indicates whether the object is disposed. */ public var disposed: Bool { - get { - return _disposed - } + return _disposed } /** diff --git a/RxSwift/Errors.swift b/RxSwift/Errors.swift index 270f101c..ccb71c19 100644 --- a/RxSwift/Errors.swift +++ b/RxSwift/Errors.swift @@ -34,11 +34,11 @@ public enum RxError */ case ArgumentOutOfRange /** - Sequence doesn't contain any element. + Sequence doesn't contain any elements. */ case NoElements /** - Sequence contains more then one element. + Sequence contains more than one element. */ case MoreThanOneElement /** @@ -62,11 +62,11 @@ public extension RxError { case .ArgumentOutOfRange: return "Argument out of range." case .NoElements: - return "Sequence doesn't contain any element." + return "Sequence doesn't contain any elements." case .MoreThanOneElement: - return "Sequence contains more then one element." + return "Sequence contains more than one element." case .Timeout: - return "Sequence timeout" + return "Sequence timeout." } } } \ No newline at end of file diff --git a/RxSwift/Event.swift b/RxSwift/Event.swift index ee259528..32b2780c 100644 --- a/RxSwift/Event.swift +++ b/RxSwift/Event.swift @@ -37,15 +37,13 @@ extension Event { - returns: Description of event */ public var debugDescription: String { - get { - switch self { - case .Next(let value): - return "Next(\(value))" - case .Error(let error): - return "Error(\(error))" - case .Completed: - return "Completed" - } + switch self { + case .Next(let value): + return "Next(\(value))" + case .Error(let error): + return "Error(\(error))" + case .Completed: + return "Completed" } } } @@ -55,35 +53,29 @@ extension Event { - returns: Is `Completed` or `Error` event */ public var isStopEvent: Bool { - get { - switch self { - case .Next: return false - case .Error, .Completed: return true - } + switch self { + case .Next: return false + case .Error, .Completed: return true } } - + /** - returns: If `Next` event, returns element value. */ public var element: Element? { - get { - if case .Next(let value) = self { - return value - } - return nil + if case .Next(let value) = self { + return value } + return nil } - + /** - returns: If `Error` event, returns error. */ public var error: ErrorType? { - get { - if case .Error(let error) = self { - return error - } - return nil + if case .Error(let error) = self { + return error } + return nil } } \ No newline at end of file diff --git a/RxSwift/Observable+Extensions.swift b/RxSwift/Observable+Extensions.swift index fb32066f..c44b9b05 100644 --- a/RxSwift/Observable+Extensions.swift +++ b/RxSwift/Observable+Extensions.swift @@ -31,7 +31,7 @@ extension ObservableType { - parameter onError: Action to invoke upon errored termination of the observable sequence. - parameter onCompleted: Action to invoke upon graceful termination of the observable sequence. - parameter onDisposed: Action to invoke upon any type of termination of sequence (if the sequence has - gracefully completed, errored, or if the generation is cancelled by disposing subscription) + gracefully completed, errored, or if the generation is cancelled by disposing subscription). - returns: Subscription object used to unsubscribe from the observable sequence. */ @warn_unused_result(message="http://git.io/rxs.ud") @@ -119,7 +119,7 @@ extension ObservableType { public extension ObservableType { /** - All internal subscribe calls go through this method + All internal subscribe calls go through this method. */ @warn_unused_result(message="http://git.io/rxs.ud") func subscribeSafe(observer: O) -> Disposable { diff --git a/RxSwift/ObservableType.swift b/RxSwift/ObservableType.swift index 4ed114cc..7594bc51 100644 --- a/RxSwift/ObservableType.swift +++ b/RxSwift/ObservableType.swift @@ -25,7 +25,7 @@ public protocol ObservableType : ObservableConvertibleType { **Next\* (Error | Completed)?** * sequences can produce zero or more elements so zero or more `Next` events can be sent to `observer` - * once an `Error` or `Completed` event is sent, the sequence terminates and can't produce any other element + * once an `Error` or `Completed` event is sent, the sequence terminates and can't produce any other elements It is possible that events are sent from different threads, but no two events can be sent concurrently to `observer`. diff --git a/RxSwift/Observables/Implementations/SingleAsync.swift b/RxSwift/Observables/Implementations/SingleAsync.swift index 38938144..af7a09ae 100644 --- a/RxSwift/Observables/Implementations/SingleAsync.swift +++ b/RxSwift/Observables/Implementations/SingleAsync.swift @@ -36,8 +36,8 @@ class SingleAsyncSink : S } if _seenValue == false { - forwardOn(.Next(value)) _seenValue = true + forwardOn(.Next(value)) } else { forwardOn(.Error(RxError.MoreThanOneElement)) dispose() diff --git a/RxSwift/Observables/Implementations/WithLatestFrom.swift b/RxSwift/Observables/Implementations/WithLatestFrom.swift index 39a7eb0c..0ac25f7d 100644 --- a/RxSwift/Observables/Implementations/WithLatestFrom.swift +++ b/RxSwift/Observables/Implementations/WithLatestFrom.swift @@ -76,9 +76,7 @@ class WithLatestFromSecond private let _disposable = SingleAssignmentDisposable() var disposed: Bool { - get { - return _disposable.disposed - } + return _disposable.disposed } init(action: Action, state: T) { diff --git a/RxSwift/Schedulers/MainScheduler.swift b/RxSwift/Schedulers/MainScheduler.swift index 7fd7d216..dfda88c8 100644 --- a/RxSwift/Schedulers/MainScheduler.swift +++ b/RxSwift/Schedulers/MainScheduler.swift @@ -34,6 +34,12 @@ public final class MainScheduler : SerialDispatchQueueScheduler { */ public static let instance = MainScheduler() + /** + Singleton instance of `MainScheduler` that always schedules work asynchronously + and doesn't perform optimizations for calls scheduled from main thread. + */ + public static let asyncInstance = SerialDispatchQueueScheduler(serialQueue: dispatch_get_main_queue()) + /** In case this method is called on a background thread it will throw an exception. */ diff --git a/RxSwift/Schedulers/SerialDispatchQueueScheduler.swift b/RxSwift/Schedulers/SerialDispatchQueueScheduler.swift index 3d30d630..82e83e3b 100644 --- a/RxSwift/Schedulers/SerialDispatchQueueScheduler.swift +++ b/RxSwift/Schedulers/SerialDispatchQueueScheduler.swift @@ -35,9 +35,7 @@ public class SerialDispatchQueueScheduler: SchedulerType { - returns: Current time. */ public var now : NSDate { - get { - return NSDate() - } + return NSDate() } // leeway for scheduling timers diff --git a/RxSwift/Schedulers/VirtualTimeScheduler.swift b/RxSwift/Schedulers/VirtualTimeScheduler.swift index 03b542ae..41716839 100644 --- a/RxSwift/Schedulers/VirtualTimeScheduler.swift +++ b/RxSwift/Schedulers/VirtualTimeScheduler.swift @@ -251,9 +251,7 @@ extension VirtualTimeScheduler { A textual representation of `self`, suitable for debugging. */ public var debugDescription: String { - get { - return self._schedulerQueue.debugDescription - } + return self._schedulerQueue.debugDescription } } @@ -266,9 +264,7 @@ class VirtualSchedulerItem