diff --git a/CHANGELOG.md b/CHANGELOG.md index d686d7e8..77320a5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,32 @@ All notable changes to this project will be documented in this file. --- +## [2.0.0-alpha.4](https://github.com/ReactiveX/RxSwift/releases/tag/2.0.0-alpha.4) + +#### Updated + +* Adds `tvOS` support +* Adds `watchOS` support +* Adds auto loading example to example app +* Restores old `Variable` behavior. Variable doesn't send anything on dealloc. +* Adds performance tests target. +* Adds more detailed resource tracing during unit tests (important for further optimizations). +* Adds `UIStepper` extensions. +* Adds `UIBarButtonItem` enabled property wrapper. +* Adds response data to userInfo of error for `rx_response` extensions of `NSURLSession`. +* Adds `onNext`, `onError` and `onCompleted` convenience methods to `ObserverType`. + +#### Fixed + +* Fixes problem on some systems with unregistering `CurrentThreadScheduler` from current thread. +* Fixes retry parameter naming (`maxAttemptCount`). +* Fixes a lot of unit test warnings. +* Removes embedding of Swift library with built frameworks. + ## [2.0.0-alpha.3](https://github.com/ReactiveX/RxSwift/releases/tag/2.0.0-alpha.3) +#### Updated + * Renames `ImmediateScheduler` protocol to `ImmediateSchedulerType` * Renames `Scheduler` protocol to `SchedulerType` * Adds `CurrentThreadScheduler` diff --git a/Documentation/API.md b/Documentation/API.md index 112eb515..e0549f25 100644 --- a/Documentation/API.md +++ b/Documentation/API.md @@ -61,6 +61,7 @@ Operators are stateless by default. #### Conditional and Boolean Operators * [`amb`](http://reactivex.io/documentation/operators/amb.html) + * [`skipWhile`](http://reactivex.io/documentation/operators/skipwhile.html) * [`takeUntil`](http://reactivex.io/documentation/operators/takeuntil.html) * [`takeWhile`](http://reactivex.io/documentation/operators/takewhile.html) diff --git a/Documentation/Examples.md b/Documentation/Examples.md index 8a8dec63..40adb9b8 100644 --- a/Documentation/Examples.md +++ b/Documentation/Examples.md @@ -56,14 +56,14 @@ let c = combineLatest(a, b) { $0 + $1 } // combines latest values of variabl // To pull values out of rx variable `c`, subscribe to values from `c`. // `subscribeNext` means subscribe to next (fresh) values of variable `c`. // That also includes the inital value "3 is positive". -c.subscribeNext { println($0) } // prints: "3 is positive" +c.subscribeNext { print($0) } // prints: "3 is positive" // Now let's increase the value of `a` // a = 4 is in RxSwift a.next(4) // prints: 6 is positive // Sum of latest values is now `4 + 2`, `6` is >= 0, map operator // produces "6 is positive" and that result is "assigned" to `c`. -// Since the value of `c` changed, `{ println($0) }` will get called, +// Since the value of `c` changed, `{ print($0) }` will get called, // and "6 is positive" is printed. // Now let's change the value of `b` @@ -73,7 +73,7 @@ b.next(-8) // doesn't print anything // get executed. // That means that `c` still contains "6 is positive" and that's correct. // Since `c` hasn't been updated, that means next value hasn't been produced, -// and `{ println($0) }` won't be called. +// and `{ print($0) }` won't be called. // ... ``` diff --git a/README.md b/README.md index 3c89325b..30b1ef8b 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,7 @@ extension UISearchBar { return proxyForObject(self) as RxSearchBarDelegateProxy } - public var rx_searchText: Observable { + public var rx_text: Observable { return defer { [weak self] in let text = self?.text ?? "" @@ -341,7 +341,7 @@ This is how that API can be now used ```swift -searchBar.rx_searchText +searchBar.rx_text .subscribeNext { searchText in print("Current search text '\(searchText)'") } @@ -454,6 +454,8 @@ Open Rx.xcworkspace, choose `RxExample` and hit run. This method will build ever ### [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html) +**:warning: IMPORTANT! For tvOS support through CocoaPods use [this hack](https://github.com/orta/cocoapods-expert-difficulty) until `0.39` is released. :warning:** + ``` # Podfile use_frameworks! @@ -474,7 +476,7 @@ $ pod install Add this to `Cartfile` ``` -git "git@github.com:ReactiveX/RxSwift.git" "2.0.0-alpha.3" +git "git@github.com:ReactiveX/RxSwift.git" "2.0.0-alpha.4" ``` ``` diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index 253c18d6..c6e0a40e 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -298,10 +298,6 @@ 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 */; }; C88254361B8A752B00B02D69 /* UITextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88254141B8A752B00B02D69 /* UITextView+Rx.swift */; }; - C8A468C81B8A892A00BF917B /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A56AD71AD7424700B4673B /* RxSwift.framework */; }; - C8A468C91B8A893400BF917B /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C88BB8711B07E5ED0064D411 /* RxSwift.framework */; }; - C8A468CA1B8A893A00BF917B /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A56AD71AD7424700B4673B /* RxSwift.framework */; }; - C8A468CB1B8A894100BF917B /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C88BB8711B07E5ED0064D411 /* RxSwift.framework */; }; C8C3D9FE1B935EDF004D233E /* Zip+CollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3D9FD1B935EDF004D233E /* Zip+CollectionType.swift */; }; C8C3D9FF1B935EDF004D233E /* Zip+CollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3D9FD1B935EDF004D233E /* Zip+CollectionType.swift */; }; C8C3DA031B9390C4004D233E /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3DA021B9390C4004D233E /* Just.swift */; }; @@ -316,8 +312,6 @@ C8C3DA101B939767004D233E /* CurrentThreadScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3DA0E1B939767004D233E /* CurrentThreadScheduler.swift */; }; C8C3DA121B93A3EA004D233E /* AnonymousObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3DA111B93A3EA004D233E /* AnonymousObservable.swift */; }; C8C3DA131B93A3EA004D233E /* AnonymousObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3DA111B93A3EA004D233E /* AnonymousObservable.swift */; }; - C8DD8F4C1BBE79190046F35C /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2EA280C1BB9B5A200880ED3 /* RxSwift.framework */; }; - C8DD8F4D1BBE79260046F35C /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2EA280C1BB9B5A200880ED3 /* RxSwift.framework */; }; C8F0BF921BBBFB8B001B112F /* Observable+Creation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093C981B8A72BE0088E94D /* Observable+Creation.swift */; }; C8F0BF931BBBFB8B001B112F /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093C4D1B8A72BE0088E94D /* ConnectableObservableType.swift */; }; C8F0BF941BBBFB8B001B112F /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3DA021B9390C4004D233E /* Just.swift */; }; @@ -546,6 +540,11 @@ D2138C971BB9BEE700339B5C /* RxCLLocationManagerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093E9A1B8A732E0088E94D /* RxCLLocationManagerDelegateProxy.swift */; }; D2138C981BB9BEEE00339B5C /* RxCocoa.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093E9B1B8A732E0088E94D /* RxCocoa.swift */; }; D2138C991BB9BEEE00339B5C /* RxTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093E9C1B8A732E0088E94D /* RxTarget.swift */; }; + D21C29311BC6A1C300448E70 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285BAC31BC0231000B3F602 /* SkipUntil.swift */; }; + D22B6D261BC8504A00BCE0AB /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22B6D251BC8504A00BCE0AB /* SkipWhile.swift */; }; + D2752D621BC5551A0070C418 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285BAC31BC0231000B3F602 /* SkipUntil.swift */; }; + D2752D631BC5551B0070C418 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285BAC31BC0231000B3F602 /* SkipUntil.swift */; }; + D285BAC41BC0231000B3F602 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285BAC31BC0231000B3F602 /* SkipUntil.swift */; }; D2EBEADC1BB9B697003A27DC /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093C491B8A72BE0088E94D /* Cancelable.swift */; }; D2EBEADD1BB9B697003A27DC /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093C4D1B8A72BE0088E94D /* ConnectableObservableType.swift */; }; D2EBEADE1BB9B697003A27DC /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093C521B8A72BE0088E94D /* Disposable.swift */; }; @@ -652,9 +651,71 @@ D2EBEB431BB9B6DE003A27DC /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093CC11B8A72BE0088E94D /* SubjectType.swift */; }; D2EBEB441BB9B6DE003A27DC /* Variable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093CC21B8A72BE0088E94D /* Variable.swift */; }; D2EBEB8A1BB9B9EE003A27DC /* Observable+Blocking.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8093F581B8A73A20088E94D /* Observable+Blocking.swift */; }; + D2FC15B31BCB95E5007361FF /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22B6D251BC8504A00BCE0AB /* SkipWhile.swift */; }; + D2FC15B41BCB95E7007361FF /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22B6D251BC8504A00BCE0AB /* SkipWhile.swift */; }; + D2FC15B51BCB95E8007361FF /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22B6D251BC8504A00BCE0AB /* SkipWhile.swift */; }; F31F35B01BB4FED800961002 /* UIStepper+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31F35AF1BB4FED800961002 /* UIStepper+Rx.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + C872BD1B1BC0529600D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = C8A56AD61AD7424700B4673B; + remoteInfo = "RxSwift-iOS"; + }; + C872BD1D1BC052A200D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = C88BB81A1B07E5ED0064D411; + remoteInfo = "RxSwift-OSX"; + }; + C872BD1F1BC052A800D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2EA280B1BB9B5A200880ED3; + remoteInfo = "RxSwift-tvOS"; + }; + C872BD211BC052AC00D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = C8F0BF901BBBFB8B001B112F; + remoteInfo = "RxSwift-watchOS"; + }; + C872BD231BC052B800D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = C8A56AD61AD7424700B4673B; + remoteInfo = "RxSwift-iOS"; + }; + C872BD251BC052BB00D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = C88BB81A1B07E5ED0064D411; + remoteInfo = "RxSwift-OSX"; + }; + C872BD271BC052BF00D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2EA280B1BB9B5A200880ED3; + remoteInfo = "RxSwift-tvOS"; + }; + C872BD291BC052C200D7175E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C8A56ACE1AD7424700B4673B /* Project object */; + proxyType = 1; + remoteGlobalIDString = C8F0BF901BBBFB8B001B112F; + remoteInfo = "RxSwift-watchOS"; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ A111CE961B91C97C00D0DCEE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C809396D1B8A71760088E94D /* RxCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -844,6 +905,8 @@ C8F0C04B1BBBFBB9001B112F /* RxCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C8F0C0581BBBFBCE001B112F /* RxBlocking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxBlocking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2138C751BB9BE9800339B5C /* RxCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D22B6D251BC8504A00BCE0AB /* SkipWhile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkipWhile.swift; sourceTree = ""; }; + D285BAC31BC0231000B3F602 /* SkipUntil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkipUntil.swift; sourceTree = ""; }; D2EA280C1BB9B5A200880ED3 /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2EBEB811BB9B99D003A27DC /* RxBlocking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxBlocking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F31F35AF1BB4FED800961002 /* UIStepper+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStepper+Rx.swift"; sourceTree = ""; }; @@ -854,7 +917,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C8A468C81B8A892A00BF917B /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -862,7 +924,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C8A468C91B8A893400BF917B /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -870,7 +931,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C8A468CA1B8A893A00BF917B /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -878,7 +938,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C8A468CB1B8A894100BF917B /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -921,7 +980,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C8DD8F4D1BBE79260046F35C /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -936,7 +994,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C8DD8F4C1BBE79190046F35C /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1069,6 +1126,7 @@ C8093C871B8A72BE0088E94D /* Scan.swift */, C8093C881B8A72BE0088E94D /* Sink.swift */, C8093C891B8A72BE0088E94D /* Skip.swift */, + D285BAC31BC0231000B3F602 /* SkipUntil.swift */, C8093C8A1B8A72BE0088E94D /* StartWith.swift */, C8093C8B1B8A72BE0088E94D /* SubscribeOn.swift */, C8093C8C1B8A72BE0088E94D /* Switch.swift */, @@ -1081,6 +1139,7 @@ C8093C921B8A72BE0088E94D /* Zip+arity.swift */, C8093C931B8A72BE0088E94D /* Zip+arity.tt */, C8C3D9FD1B935EDF004D233E /* Zip+CollectionType.swift */, + D22B6D251BC8504A00BCE0AB /* SkipWhile.swift */, ); path = Implementations; sourceTree = ""; @@ -1446,6 +1505,7 @@ buildRules = ( ); dependencies = ( + C872BD1C1BC0529600D7175E /* PBXTargetDependency */, ); name = "RxCocoa-iOS"; productName = RxSwift; @@ -1464,6 +1524,7 @@ buildRules = ( ); dependencies = ( + C872BD1E1BC052A200D7175E /* PBXTargetDependency */, ); name = "RxCocoa-OSX"; productName = RxSwift; @@ -1482,6 +1543,7 @@ buildRules = ( ); dependencies = ( + C872BD241BC052B800D7175E /* PBXTargetDependency */, ); name = "RxBlocking-iOS"; productName = RxSwift; @@ -1500,6 +1562,7 @@ buildRules = ( ); dependencies = ( + C872BD261BC052BB00D7175E /* PBXTargetDependency */, ); name = "RxBlocking-OSX"; productName = RxSwift; @@ -1572,6 +1635,7 @@ buildRules = ( ); dependencies = ( + C872BD221BC052AC00D7175E /* PBXTargetDependency */, ); name = "RxCocoa-watchOS"; productName = RxSwift; @@ -1590,6 +1654,7 @@ buildRules = ( ); dependencies = ( + C872BD2A1BC052C200D7175E /* PBXTargetDependency */, ); name = "RxBlocking-watchOS"; productName = RxSwift; @@ -1608,6 +1673,7 @@ buildRules = ( ); dependencies = ( + C872BD201BC052A800D7175E /* PBXTargetDependency */, ); name = "RxCocoa-tvOS"; productName = "RxCocoa-tvOS"; @@ -1644,6 +1710,7 @@ buildRules = ( ); dependencies = ( + C872BD281BC052BF00D7175E /* PBXTargetDependency */, ); name = "RxBlocking-tvOS"; productName = "RxBlocking-tvOS"; @@ -1936,6 +2003,7 @@ C8093D041B8A72BE0088E94D /* AsObservable.swift in Sources */, C8093D061B8A72BE0088E94D /* Catch.swift in Sources */, C8093D0C1B8A72BE0088E94D /* CombineLatest.swift in Sources */, + D2FC15B31BCB95E5007361FF /* SkipWhile.swift in Sources */, C8093D5E1B8A72BE0088E94D /* Observable+Multiple.swift in Sources */, C8093D741B8A72BE0088E94D /* ObserverBase.swift in Sources */, C8093D121B8A72BE0088E94D /* ConnectableObservable.swift in Sources */, @@ -1947,6 +2015,7 @@ C8093CD81B8A72BE0088E94D /* BinaryDisposable.swift in Sources */, C8093D2A1B8A72BE0088E94D /* ObserveOn.swift in Sources */, C8093D361B8A72BE0088E94D /* Sample.swift in Sources */, + D2752D621BC5551A0070C418 /* SkipUntil.swift in Sources */, C8093CEA1B8A72BE0088E94D /* ScopedDisposable.swift in Sources */, C8093D261B8A72BE0088E94D /* Multicast.swift in Sources */, C8C3DA101B939767004D233E /* CurrentThreadScheduler.swift in Sources */, @@ -2048,6 +2117,7 @@ C8093D031B8A72BE0088E94D /* AsObservable.swift in Sources */, C8093D051B8A72BE0088E94D /* Catch.swift in Sources */, C8093D0B1B8A72BE0088E94D /* CombineLatest.swift in Sources */, + D22B6D261BC8504A00BCE0AB /* SkipWhile.swift in Sources */, C8093D5D1B8A72BE0088E94D /* Observable+Multiple.swift in Sources */, C8093D731B8A72BE0088E94D /* ObserverBase.swift in Sources */, C8093D111B8A72BE0088E94D /* ConnectableObservable.swift in Sources */, @@ -2059,6 +2129,7 @@ C8093CD71B8A72BE0088E94D /* BinaryDisposable.swift in Sources */, C8093D291B8A72BE0088E94D /* ObserveOn.swift in Sources */, C8093D351B8A72BE0088E94D /* Sample.swift in Sources */, + D285BAC41BC0231000B3F602 /* SkipUntil.swift in Sources */, C8093CE91B8A72BE0088E94D /* ScopedDisposable.swift in Sources */, C8093D251B8A72BE0088E94D /* Multicast.swift in Sources */, C8C3DA0F1B939767004D233E /* CurrentThreadScheduler.swift in Sources */, @@ -2160,6 +2231,7 @@ C8F0BFAB1BBBFB8B001B112F /* AsObservable.swift in Sources */, C8F0BFAC1BBBFB8B001B112F /* Catch.swift in Sources */, C8F0BFAD1BBBFB8B001B112F /* CombineLatest.swift in Sources */, + D2FC15B51BCB95E8007361FF /* SkipWhile.swift in Sources */, C8F0BFAE1BBBFB8B001B112F /* Observable+Multiple.swift in Sources */, C8F0BFAF1BBBFB8B001B112F /* ObserverBase.swift in Sources */, C8F0BFB01BBBFB8B001B112F /* ConnectableObservable.swift in Sources */, @@ -2171,6 +2243,7 @@ C8F0BFB61BBBFB8B001B112F /* BinaryDisposable.swift in Sources */, C8F0BFB71BBBFB8B001B112F /* ObserveOn.swift in Sources */, C8F0BFB81BBBFB8B001B112F /* Sample.swift in Sources */, + D21C29311BC6A1C300448E70 /* SkipUntil.swift in Sources */, C8F0BFB91BBBFB8B001B112F /* ScopedDisposable.swift in Sources */, C8F0BFBA1BBBFB8B001B112F /* Multicast.swift in Sources */, C8F0BFBB1BBBFB8B001B112F /* CurrentThreadScheduler.swift in Sources */, @@ -2406,6 +2479,7 @@ D2EBEB381BB9B6D8003A27DC /* ConcurrentDispatchQueueScheduler.swift in Sources */, D2EBEB131BB9B6C1003A27DC /* Multicast.swift in Sources */, D2EBEB111BB9B6C1003A27DC /* Map.swift in Sources */, + D2FC15B41BCB95E7007361FF /* SkipWhile.swift in Sources */, D2EBEB071BB9B6C1003A27DC /* Deferred.swift in Sources */, D2EBEB2C1BB9B6CA003A27DC /* Observable+Binding.swift in Sources */, D2EBEB041BB9B6C1003A27DC /* Concat.swift in Sources */, @@ -2417,6 +2491,7 @@ D2EBEB2A1BB9B6C5003A27DC /* Zip+CollectionType.swift in Sources */, D2EBEB401BB9B6DE003A27DC /* BehaviorSubject.swift in Sources */, D2EBEB271BB9B6C1003A27DC /* Timer.swift in Sources */, + D2752D631BC5551B0070C418 /* SkipUntil.swift in Sources */, D2EBEB351BB9B6D2003A27DC /* ObserverBase.swift in Sources */, D2EBEB0F1BB9B6C1003A27DC /* Generate.swift in Sources */, D2EBEB1F1BB9B6C1003A27DC /* Skip.swift in Sources */, @@ -2496,6 +2571,49 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + C872BD1C1BC0529600D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C8A56AD61AD7424700B4673B /* RxSwift-iOS */; + targetProxy = C872BD1B1BC0529600D7175E /* PBXContainerItemProxy */; + }; + C872BD1E1BC052A200D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C88BB81A1B07E5ED0064D411 /* RxSwift-OSX */; + targetProxy = C872BD1D1BC052A200D7175E /* PBXContainerItemProxy */; + }; + C872BD201BC052A800D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D2EA280B1BB9B5A200880ED3 /* RxSwift-tvOS */; + targetProxy = C872BD1F1BC052A800D7175E /* PBXContainerItemProxy */; + }; + C872BD221BC052AC00D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C8F0BF901BBBFB8B001B112F /* RxSwift-watchOS */; + targetProxy = C872BD211BC052AC00D7175E /* PBXContainerItemProxy */; + }; + C872BD241BC052B800D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C8A56AD61AD7424700B4673B /* RxSwift-iOS */; + targetProxy = C872BD231BC052B800D7175E /* PBXContainerItemProxy */; + }; + C872BD261BC052BB00D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C88BB81A1B07E5ED0064D411 /* RxSwift-OSX */; + targetProxy = C872BD251BC052BB00D7175E /* PBXContainerItemProxy */; + }; + C872BD281BC052BF00D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D2EA280B1BB9B5A200880ED3 /* RxSwift-tvOS */; + targetProxy = C872BD271BC052BF00D7175E /* PBXContainerItemProxy */; + }; + C872BD2A1BC052C200D7175E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C8F0BF901BBBFB8B001B112F /* RxSwift-watchOS */; + targetProxy = C872BD291BC052C200D7175E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ C809396A1B8A71760088E94D /* Debug */ = { isa = XCBuildConfiguration; diff --git a/RxBlocking.podspec b/RxBlocking.podspec index fdfb7aa5..fce3d161 100644 --- a/RxBlocking.podspec +++ b/RxBlocking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "RxBlocking" - s.version = "2.0.0-alpha.3" + s.version = "2.0.0-alpha.4" s.summary = "RxSwift Blocking operatos" s.description = <<-DESC Set of blocking operators for unit testing @@ -15,6 +15,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' s.watchos.deployment_target = '2.0' + s.tvos.deployment_target = '9.0' s.source_files = 'RxBlocking/**/*.swift' diff --git a/RxBlocking/Observable+Blocking.swift b/RxBlocking/Observable+Blocking.swift index 8b5c56cc..799cbf98 100644 --- a/RxBlocking/Observable+Blocking.swift +++ b/RxBlocking/Observable+Blocking.swift @@ -28,7 +28,7 @@ extension ObservableType { var ended = false - self.subscribe { e in + _ = self.subscribe { e in switch e { case .Next(let element): elements.append(element) diff --git a/RxCocoa.podspec b/RxCocoa.podspec index c2360877..6d087620 100644 --- a/RxCocoa.podspec +++ b/RxCocoa.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "RxCocoa" - s.version = "2.0.0-alpha.3" + s.version = "2.0.0-alpha.4" s.summary = "RxSwift Cocoa extensions" s.description = <<-DESC * UI extensions @@ -17,11 +17,13 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' s.watchos.deployment_target = '2.0' + s.tvos.deployment_target = '9.0' s.source_files = 'RxCocoa/RxCocoa.h', 'RxCocoa/Common/**/*.{swift,h,m}' s.ios.source_files = 'RxCocoa/iOS/**/*.swift' s.osx.source_files = 'RxCocoa/OSX/**/*.swift' s.watchos.source_files = 'RxCocoa/iOS/**/*.swift' + s.tvos.source_files = 'RxCocoa/iOS/**/*.swift' s.dependency 'RxSwift', '~> 2.0.0-alpha' end diff --git a/RxCocoa/Common/DelegateProxyType.swift b/RxCocoa/Common/DelegateProxyType.swift index 562f0078..5b7b77fa 100644 --- a/RxCocoa/Common/DelegateProxyType.swift +++ b/RxCocoa/Common/DelegateProxyType.swift @@ -160,7 +160,7 @@ Returns existing proxy for object or installs new instance of delegate proxy. return proxyForObject(self) as RxSearchBarDelegateProxy } - public var rx_searchText: ControlProperty { + public var rx_text: ControlProperty { let source: Observable = self.rx_delegate.observe("searchBar:textDidChange:") ... } diff --git a/RxExample/RxExample.xcodeproj/project.pbxproj b/RxExample/RxExample.xcodeproj/project.pbxproj index 7c493ad7..01ac11d0 100644 --- a/RxExample/RxExample.xcodeproj/project.pbxproj +++ b/RxExample/RxExample.xcodeproj/project.pbxproj @@ -45,7 +45,6 @@ C8297E481B6CF905000589EA /* Differentiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88C78941B3F20DB0061C5AB /* Differentiator.swift */; }; C8297E491B6CF905000589EA /* WikipediaSearchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C46DA51B47F7110020D71E /* WikipediaSearchCell.swift */; }; C8297E4A1B6CF905000589EA /* GitHubSignupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C890A6571AEBD26B00AFF7E6 /* GitHubSignupViewController.swift */; }; - C8297E4B1B6CF905000589EA /* Random.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C8A57F721B40AF7C00D5570A /* Random.xcdatamodeld */; }; C8297E4C1B6CF905000589EA /* APIWrappersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075F130F1B4E9D5A000D7861 /* APIWrappersViewController.swift */; }; C8297E4D1B6CF905000589EA /* RxTableViewSectionedReloadDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88C78651B3EB0A00061C5AB /* RxTableViewSectionedReloadDataSource.swift */; }; C8297E4E1B6CF905000589EA /* RxCollectionViewSectionedAnimatedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C859B9A91B45CB0900D012D7 /* RxCollectionViewSectionedAnimatedDataSource.swift */; }; @@ -277,7 +276,6 @@ C8A468F11B8A8C2600BF917B /* RxBlocking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A468EF1B8A8BD000BF917B /* RxBlocking.framework */; }; C8A468F21B8A8C2600BF917B /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A468ED1B8A8BCC00BF917B /* RxCocoa.framework */; }; C8A468F31B8A8C2600BF917B /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8A468EB1B8A8BC900BF917B /* RxSwift.framework */; }; - C8A57F741B40AF7C00D5570A /* Random.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C8A57F721B40AF7C00D5570A /* Random.xcdatamodeld */; }; C8A7501F1B94E77C00D8D046 /* RxDataSourceStarterKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8A7501E1B94E77C00D8D046 /* RxDataSourceStarterKit.swift */; }; C8A750201B94E78200D8D046 /* RxDataSourceStarterKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8A7501E1B94E77C00D8D046 /* RxDataSourceStarterKit.swift */; }; C8C46DA81B47F7110020D71E /* CollectionViewImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C46DA31B47F7110020D71E /* CollectionViewImageCell.swift */; }; @@ -294,9 +292,98 @@ C8DF92EA1B0B38C0009BCF9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C8DF92E91B0B38C0009BCF9A /* Images.xcassets */; }; C8DF92EB1B0B38C0009BCF9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C8DF92E91B0B38C0009BCF9A /* Images.xcassets */; }; C8DF92F61B0B43A4009BCF9A /* IntroductionExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8DF92F51B0B43A4009BCF9A /* IntroductionExampleViewController.swift */; }; + D245D9F41BC6CA0900CAB388 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D245D9E61BC6C60800CAB388 /* SkipUntil.swift */; }; + D2FC15C41BCBAA13007361FF /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FC15B61BCBAA01007361FF /* SkipWhile.swift */; }; EC91FB951BBA144400973245 /* GitHubSearchRepositoriesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC91FB941BBA144400973245 /* GitHubSearchRepositoriesViewController.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + C81B3A001BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C8A56AD71AD7424700B4673B; + remoteInfo = "RxSwift-iOS"; + }; + C81B3A021BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C88BB8711B07E5ED0064D411; + remoteInfo = "RxSwift-OSX"; + }; + C81B3A041BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2EA280C1BB9B5A200880ED3; + remoteInfo = "RxSwift-tvOS"; + }; + C81B3A061BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C8F0C0021BBBFB8B001B112F; + remoteInfo = "RxSwift-watchOS"; + }; + C81B3A081BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C809396D1B8A71760088E94D; + remoteInfo = "RxCocoa-iOS"; + }; + C81B3A0A1BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C80939E71B8A71840088E94D; + remoteInfo = "RxCocoa-OSX"; + }; + C81B3A0C1BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2138C751BB9BE9800339B5C; + remoteInfo = "RxCocoa-tvOS"; + }; + C81B3A0E1BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C8F0C04B1BBBFBB9001B112F; + remoteInfo = "RxCocoa-watchOS"; + }; + C81B3A101BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C8093BC71B8A71F00088E94D; + remoteInfo = "RxBlocking-iOS"; + }; + C81B3A121BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C8093C451B8A71FC0088E94D; + remoteInfo = "RxBlocking-OSX"; + }; + C81B3A141BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2EBEB811BB9B99D003A27DC; + remoteInfo = "RxBlocking-tvOS"; + }; + C81B3A161BC1C28400EF5A9F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C8F0C0581BBBFBCE001B112F; + remoteInfo = "RxBlocking-watchOS"; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ C8297E621B6CF905000589EA /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -343,6 +430,7 @@ 07E300061B14995F00F00100 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 07E300081B149A2A00F00100 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 07E3C2321B03605B0010338D /* Dependencies.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Dependencies.swift; path = Examples/Dependencies.swift; sourceTree = ""; }; + C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Rx.xcodeproj; path = ../Rx.xcodeproj; sourceTree = ""; }; C8297E691B6CF905000589EA /* RxExample-iOS-no-module.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "RxExample-iOS-no-module.app"; sourceTree = BUILT_PRODUCTS_DIR; }; C83366DD1AD0293800C668A7 /* RxExample-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "RxExample-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; C833670F1AD029AE00C668A7 /* Example.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Example.swift; sourceTree = ""; }; @@ -547,7 +635,6 @@ C8A468EB1B8A8BC900BF917B /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C8A468ED1B8A8BCC00BF917B /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = RxCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C8A468EF1B8A8BD000BF917B /* RxBlocking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = RxBlocking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C8A57F731B40AF7C00D5570A /* Random.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Random.xcdatamodel; sourceTree = ""; }; C8A7501E1B94E77C00D8D046 /* RxDataSourceStarterKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxDataSourceStarterKit.swift; sourceTree = ""; }; C8AF26F11B49ABD300131C03 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; C8C46DA31B47F7110020D71E /* CollectionViewImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewImageCell.swift; sourceTree = ""; }; @@ -565,6 +652,8 @@ C8DF92F01B0B3E67009BCF9A /* Info-OSX.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-OSX.plist"; sourceTree = ""; }; C8DF92F21B0B3E71009BCF9A /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; C8DF92F51B0B43A4009BCF9A /* IntroductionExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = IntroductionExampleViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + D245D9E61BC6C60800CAB388 /* SkipUntil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkipUntil.swift; sourceTree = ""; }; + D2FC15B61BCBAA01007361FF /* SkipWhile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkipWhile.swift; sourceTree = ""; }; EC91FB941BBA144400973245 /* GitHubSearchRepositoriesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GitHubSearchRepositoriesViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -655,9 +744,29 @@ path = TableView; sourceTree = ""; }; + C81B39F21BC1C28400EF5A9F /* Products */ = { + isa = PBXGroup; + children = ( + C81B3A011BC1C28400EF5A9F /* RxSwift.framework */, + C81B3A031BC1C28400EF5A9F /* RxSwift.framework */, + C81B3A051BC1C28400EF5A9F /* RxSwift.framework */, + C81B3A071BC1C28400EF5A9F /* RxSwift.framework */, + C81B3A091BC1C28400EF5A9F /* RxCocoa.framework */, + C81B3A0B1BC1C28400EF5A9F /* RxCocoa.framework */, + C81B3A0D1BC1C28400EF5A9F /* RxCocoa.framework */, + C81B3A0F1BC1C28400EF5A9F /* RxCocoa.framework */, + C81B3A111BC1C28400EF5A9F /* RxBlocking.framework */, + C81B3A131BC1C28400EF5A9F /* RxBlocking.framework */, + C81B3A151BC1C28400EF5A9F /* RxBlocking.framework */, + C81B3A171BC1C28400EF5A9F /* RxBlocking.framework */, + ); + name = Products; + sourceTree = ""; + }; C83366D41AD0293800C668A7 = { isa = PBXGroup; children = ( + C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */, C8A468EF1B8A8BD000BF917B /* RxBlocking.framework */, C8A468ED1B8A8BCC00BF917B /* RxCocoa.framework */, C8A468EB1B8A8BC900BF917B /* RxSwift.framework */, @@ -974,6 +1083,8 @@ C864093C1BA5909000D3C4E8 /* Implementations */ = { isa = PBXGroup; children = ( + D2FC15B61BCBAA01007361FF /* SkipWhile.swift */, + D245D9E61BC6C60800CAB388 /* SkipUntil.swift */, C864093D1BA5909000D3C4E8 /* Amb.swift */, C864093E1BA5909000D3C4E8 /* AnonymousObservable.swift */, C864093F1BA5909000D3C4E8 /* AsObservable.swift */, @@ -1075,8 +1186,7 @@ 07E300051B14994500F00100 /* 05 TableView */, 07A5C3D91B70B6B8001EFE5C /* 06 Calculator */, C859B9A21B45C5D900D012D7 /* 07 PartialUpdates */, - C8A57F711B40AF4E00D5570A /* 08 CoreData */, - EC91FB931BBA12E800973245 /* 09 AutoLoading */, + EC91FB931BBA12E800973245 /* 08 AutoLoading */, ); path = Examples; sourceTree = ""; @@ -1162,15 +1272,6 @@ path = DataSources; sourceTree = ""; }; - C8A57F711B40AF4E00D5570A /* 08 CoreData */ = { - isa = PBXGroup; - children = ( - C8A57F721B40AF7C00D5570A /* Random.xcdatamodeld */, - ); - name = "08 CoreData"; - path = CoreData; - sourceTree = ""; - }; C8DF92C71B0B2F84009BCF9A /* iOS */ = { isa = PBXGroup; children = ( @@ -1200,12 +1301,12 @@ path = Introduction; sourceTree = ""; }; - EC91FB931BBA12E800973245 /* 09 AutoLoading */ = { + EC91FB931BBA12E800973245 /* 08 AutoLoading */ = { isa = PBXGroup; children = ( EC91FB941BBA144400973245 /* GitHubSearchRepositoriesViewController.swift */, ); - name = "09 AutoLoading"; + name = "08 AutoLoading"; path = AutoLoading; sourceTree = ""; }; @@ -1292,6 +1393,12 @@ mainGroup = C83366D41AD0293800C668A7; productRefGroup = C83366DE1AD0293800C668A7 /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = C81B39F21BC1C28400EF5A9F /* Products */; + ProjectRef = C81B39F11BC1C28400EF5A9F /* Rx.xcodeproj */; + }, + ); projectRoot = ""; targets = ( C83366DC1AD0293800C668A7 /* RxExample-iOS */, @@ -1301,6 +1408,93 @@ }; /* End PBXProject section */ +/* Begin PBXReferenceProxy section */ + C81B3A011BC1C28400EF5A9F /* RxSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxSwift.framework; + remoteRef = C81B3A001BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A031BC1C28400EF5A9F /* RxSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxSwift.framework; + remoteRef = C81B3A021BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A051BC1C28400EF5A9F /* RxSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxSwift.framework; + remoteRef = C81B3A041BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A071BC1C28400EF5A9F /* RxSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxSwift.framework; + remoteRef = C81B3A061BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A091BC1C28400EF5A9F /* RxCocoa.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxCocoa.framework; + remoteRef = C81B3A081BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A0B1BC1C28400EF5A9F /* RxCocoa.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxCocoa.framework; + remoteRef = C81B3A0A1BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A0D1BC1C28400EF5A9F /* RxCocoa.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxCocoa.framework; + remoteRef = C81B3A0C1BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A0F1BC1C28400EF5A9F /* RxCocoa.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxCocoa.framework; + remoteRef = C81B3A0E1BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A111BC1C28400EF5A9F /* RxBlocking.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxBlocking.framework; + remoteRef = C81B3A101BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A131BC1C28400EF5A9F /* RxBlocking.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxBlocking.framework; + remoteRef = C81B3A121BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A151BC1C28400EF5A9F /* RxBlocking.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxBlocking.framework; + remoteRef = C81B3A141BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C81B3A171BC1C28400EF5A9F /* RxBlocking.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RxBlocking.framework; + remoteRef = C81B3A161BC1C28400EF5A9F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + /* Begin PBXResourcesBuildPhase section */ C8297E5C1B6CF905000589EA /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -1404,9 +1598,11 @@ C864099D1BA5909000D3C4E8 /* NAryDisposable.swift in Sources */, C86409C51BA5909000D3C4E8 /* ObserveOn.swift in Sources */, C84B3A331BA4345A001B7D88 /* ControlProperty.swift in Sources */, + D245D9F41BC6CA0900CAB388 /* SkipUntil.swift in Sources */, C86409FA1BA5909000D3C4E8 /* Variable.swift in Sources */, C8297E3A1B6CF905000589EA /* WikipediaSearchViewController.swift in Sources */, C84B3A5A1BA4345A001B7D88 /* UIGestureRecognizer+Rx.swift in Sources */, + D2FC15C41BCBAA13007361FF /* SkipWhile.swift in Sources */, C86409AC1BA5909000D3C4E8 /* AnonymousObservable.swift in Sources */, C84B3A401BA4345A001B7D88 /* NSURLSession+Rx.swift in Sources */, C8297E3B1B6CF905000589EA /* String+extensions.swift in Sources */, @@ -1489,7 +1685,6 @@ C864099C1BA5909000D3C4E8 /* DisposeBase.swift in Sources */, C8297E4A1B6CF905000589EA /* GitHubSignupViewController.swift in Sources */, C86409F51BA5909000D3C4E8 /* SchedulerType.swift in Sources */, - C8297E4B1B6CF905000589EA /* Random.xcdatamodeld in Sources */, C86409B81BA5909000D3C4E8 /* DelaySubscription.swift in Sources */, C84B3A641BA4345A001B7D88 /* UITextView+Rx.swift in Sources */, C86409AF1BA5909000D3C4E8 /* Catch.swift in Sources */, @@ -1591,7 +1786,6 @@ C88C78951B3F20DB0061C5AB /* Differentiator.swift in Sources */, C8C46DAA1B47F7110020D71E /* WikipediaSearchCell.swift in Sources */, C890A6581AEBD26B00AFF7E6 /* GitHubSignupViewController.swift in Sources */, - C8A57F741B40AF7C00D5570A /* Random.xcdatamodeld in Sources */, 075F13101B4E9D5A000D7861 /* APIWrappersViewController.swift in Sources */, C83367311AD029AE00C668A7 /* Wireframe.swift in Sources */, 07E300071B14995F00F00100 /* TableViewController.swift in Sources */, @@ -1928,19 +2122,6 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ - -/* Begin XCVersionGroup section */ - C8A57F721B40AF7C00D5570A /* Random.xcdatamodeld */ = { - isa = XCVersionGroup; - children = ( - C8A57F731B40AF7C00D5570A /* Random.xcdatamodel */, - ); - currentVersion = C8A57F731B40AF7C00D5570A /* Random.xcdatamodel */; - path = Random.xcdatamodeld; - sourceTree = ""; - versionGroupType = wrapper.xcdatamodel; - }; -/* End XCVersionGroup section */ }; rootObject = C83366D51AD0293800C668A7 /* Project object */; } diff --git a/RxExample/RxExample/Example.swift b/RxExample/RxExample/Example.swift index 4cd910f1..217b107b 100644 --- a/RxExample/RxExample/Example.swift +++ b/RxExample/RxExample/Example.swift @@ -35,7 +35,6 @@ extension String { } } - func showAlert(message: String) { #if os(iOS) UIAlertView(title: "RxExample", message: message, delegate: nil, cancelButtonTitle: "OK").show() diff --git a/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift b/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift index 3cfa0b22..4e81e939 100644 --- a/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift +++ b/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift @@ -194,11 +194,9 @@ class APIWrappersViewController: ViewController { // MARK: CLLocationManager - if #available(iOS 8.0, *) { - manager.requestWhenInUseAuthorization() - } else { - // Fallback on earlier versions - } + #if !RX_NO_MODULE + manager.requestWhenInUseAuthorization() + #endif manager.rx_didUpdateLocations .subscribeNext { [weak self] x in diff --git a/RxExample/RxExample/Examples/AutoLoading/GitHubSearchRepositoriesViewController.swift b/RxExample/RxExample/Examples/AutoLoading/GitHubSearchRepositoriesViewController.swift index a5d7b4d8..5852a51c 100644 --- a/RxExample/RxExample/Examples/AutoLoading/GitHubSearchRepositoriesViewController.swift +++ b/RxExample/RxExample/Examples/AutoLoading/GitHubSearchRepositoriesViewController.swift @@ -95,29 +95,31 @@ class GitHubSearchRepositoriesAPI { } private func recursivelySearch(loadedSoFar: [Repository], loadNextURL: NSURL, loadNextPageTrigger: Observable) -> Observable { - return loadSearchURL(loadNextURL).flatMap { (newPageRepositoriesResponse, nextURL) -> Observable in - // in case access denied, just stop - guard case .Repositories(let newPageRepositories) = newPageRepositoriesResponse else { - return just(newPageRepositoriesResponse) + return loadSearchURL(loadNextURL) + .retry(3) + .flatMap { (newPageRepositoriesResponse, nextURL) -> Observable in + // in case access denied, just stop + guard case .Repositories(let newPageRepositories) = newPageRepositoriesResponse else { + return just(newPageRepositoriesResponse) + } + + var loadedRepositories = loadedSoFar + loadedRepositories.appendContentsOf(newPageRepositories) + + // if next page can't be loaded, just return what was loaded, and stop + guard let nextURL = nextURL else { + return just(.Repositories(loadedRepositories)) + } + + return [ + // return loaded immediately + just(.Repositories(loadedRepositories)), + // wait until next page can be loaded + never().takeUntil(loadNextPageTrigger), + // load next page + self.recursivelySearch(loadedRepositories, loadNextURL: nextURL, loadNextPageTrigger: loadNextPageTrigger) + ].concat() } - - var loadedRepositories = loadedSoFar - loadedRepositories.appendContentsOf(newPageRepositories) - - // if next page can't be loaded, just return what was loaded, and stop - guard let nextURL = nextURL else { - return just(.Repositories(loadedRepositories)) - } - - return [ - // return loaded immediately - just(.Repositories(loadedRepositories)), - // wait until next page can be loaded - never().takeUntil(loadNextPageTrigger), - // load next page - self.recursivelySearch(loadedRepositories, loadNextURL: nextURL, loadNextPageTrigger: loadNextPageTrigger) - ].concat() - } } private func loadSearchURL(searchURL: NSURL) -> Observable<(response: SearchRepositoryResponse, nextURL: NSURL?)> { @@ -191,15 +193,13 @@ class GitHubSearchRepositoriesViewController: ViewController, UITableViewDelegat let $: Dependencies = Dependencies.sharedDependencies let tableView = self.tableView + let searchBar = self.searchBar let allRepositories = repositories .map { repositories in return [SectionModel(model: "Repositories", items: repositories)] } - tableView.rx_setDelegate(self) - .addDisposableTo(disposeBag) - dataSource.cellFactory = { (tv, ip, repository: Repository) in let cell = tv.dequeueReusableCellWithIdentifier("Cell")! cell.textLabel?.text = repository.name @@ -208,14 +208,15 @@ class GitHubSearchRepositoriesViewController: ViewController, UITableViewDelegat } dataSource.titleForHeaderInSection = { [unowned dataSource] sectionIndex in - return dataSource.sectionAtIndex(sectionIndex).model + let section = dataSource.sectionAtIndex(sectionIndex) + return section.items.count > 0 ? "Repositories (\(section.items.count))" : "No repositories found" } // reactive data source allRepositories .bindTo(tableView.rx_itemsWithDataSource(dataSource)) .addDisposableTo(disposeBag) - + let loadNextPageTrigger = tableView.rx_contentOffset .flatMap { offset in GitHubSearchRepositoriesViewController.isNearTheBottomEdge(offset, tableView) @@ -231,7 +232,6 @@ class GitHubSearchRepositoriesViewController: ViewController, UITableViewDelegat return just(.Repositories([])) } else { return GitHubSearchRepositoriesAPI.sharedAPI.search(query, loadNextPageTrigger: loadNextPageTrigger) - .retry(3) .catchErrorJustReturn(.Repositories([])) } } @@ -246,28 +246,24 @@ class GitHubSearchRepositoriesViewController: ViewController, UITableViewDelegat } } .addDisposableTo(disposeBag) + + // dismiss keyboard on scroll + tableView.rx_contentOffset + .subscribe { _ in + if searchBar.isFirstResponder() { + _ = searchBar.resignFirstResponder() + } + } + .addDisposableTo(disposeBag) + + // so normal delegate customization can also be used + tableView.rx_setDelegate(self) + .addDisposableTo(disposeBag) } - override func setEditing(editing: Bool, animated: Bool) { - super.setEditing(editing, animated: animated) - tableView.editing = editing - } - // MARK: Table view delegate - func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let title = dataSource.sectionAtIndex(section) - - let label = UILabel(frame: CGRect.zero) - label.text = " \(title)" - label.textColor = UIColor.whiteColor() - label.backgroundColor = UIColor.darkGrayColor() - label.alpha = 0.9 - - return label - } - func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return 40 + return 30 } } diff --git a/RxExample/RxExample/Examples/CoreData/Random.xcdatamodeld/Random.xcdatamodel/contents b/RxExample/RxExample/Examples/CoreData/Random.xcdatamodeld/Random.xcdatamodel/contents deleted file mode 100644 index 6b481e21..00000000 --- a/RxExample/RxExample/Examples/CoreData/Random.xcdatamodeld/Random.xcdatamodel/contents +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/RxExample/RxExample/Examples/Dependencies.swift b/RxExample/RxExample/Examples/Dependencies.swift index 8e0bef9b..ef0f02e2 100644 --- a/RxExample/RxExample/Examples/Dependencies.swift +++ b/RxExample/RxExample/Examples/Dependencies.swift @@ -25,11 +25,9 @@ class Dependencies { let operationQueue = NSOperationQueue() operationQueue.maxConcurrentOperationCount = 2 - if #available(iOS 8.0, *) { - operationQueue.qualityOfService = NSQualityOfService.UserInitiated - } else { - // Fallback on earlier versions - } + #if !RX_NO_MODULE + operationQueue.qualityOfService = NSQualityOfService.UserInitiated + #endif backgroundWorkScheduler = OperationQueueScheduler(operationQueue: operationQueue) mainScheduler = MainScheduler.sharedInstance diff --git a/RxExample/RxExample/Examples/GitHubSignup/Views/GitHubSignupViewController.swift b/RxExample/RxExample/Examples/GitHubSignup/Views/GitHubSignupViewController.swift index 09eb1755..00ebe08b 100644 --- a/RxExample/RxExample/Examples/GitHubSignup/Views/GitHubSignupViewController.swift +++ b/RxExample/RxExample/Examples/GitHubSignup/Views/GitHubSignupViewController.swift @@ -13,9 +13,6 @@ import RxSwift import RxCocoa #endif -let okColor = UIColor(red: 138.0 / 255.0, green: 221.0 / 255.0, blue: 109.0 / 255.0, alpha: 1.0) -let errorColor = UIColor.redColor() - typealias ValidationResult = (valid: Bool?, message: String?) typealias ValidationObservable = Observable @@ -30,7 +27,7 @@ class ValidationService { let minPasswordCount = 5 - func validateUsername(username: String) -> Observable { + func validateUsername(username: String) -> ValidationObservable { if username.characters.count == 0 { return just((false, nil)) } @@ -93,6 +90,11 @@ class GitHubSignupViewController : ViewController { @IBOutlet weak var signupOutlet: UIButton! @IBOutlet weak var signingUpOulet: UIActivityIndicatorView! + + struct ValidationColors { + static let okColor = UIColor(red: 138.0 / 255.0, green: 221.0 / 255.0, blue: 109.0 / 255.0, alpha: 1.0) + static let errorColor = UIColor.redColor() + } var disposeBag = DisposeBag() @@ -108,9 +110,8 @@ class GitHubSignupViewController : ViewController { let validationColor: UIColor if let valid = v.valid { - validationColor = valid ? okColor : errorColor - } - else { + validationColor = valid ? ValidationColors.okColor : ValidationColors.errorColor + } else { validationColor = UIColor.grayColor() } @@ -128,7 +129,6 @@ class GitHubSignupViewController : ViewController { super.viewDidLoad() let tapBackground = UITapGestureRecognizer(target: self, action: Selector("dismissKeyboard:")) - tapBackground.numberOfTouchesRequired = 1 view.addGestureRecognizer(tapBackground) self.disposeBag = DisposeBag() @@ -140,7 +140,7 @@ class GitHubSignupViewController : ViewController { let username = usernameOutlet.rx_text let password = passwordOutlet.rx_text let repeatPassword = repeatedPasswordOutlet.rx_text - let signupSampler = self.signupOutlet.rx_tap + let signupSampler = signupOutlet.rx_tap let usernameValidation = username .map { username in @@ -174,8 +174,11 @@ class GitHubSignupViewController : ViewController { passwordValidation, repeatPasswordValidation, signingProcess - ) { un, p, pr, signingState in - return (un.valid ?? false) && (p.valid ?? false) && (pr.valid ?? false) && signingState != SignupState.SigningUp + ) { username, password, repeatPassword, signingState in + return (username.valid ?? false) && + (password.valid ?? false) && + (repeatPassword.valid ?? false) && + signingState != SignupState.SigningUp } bindValidationResultToUI( @@ -224,11 +227,12 @@ class GitHubSignupViewController : ViewController { // This is one of the reasons why it's a good idea for disposal to be detached from allocations. // If resources weren't disposed before view controller is being deallocated, signup alert view - // could be presented on top of wrong screen or crash your app if it was being presented while - // navigation stack is popping. + // could be presented on top of the wrong screen or could crash your app if it was being presented + // while navigation stack is popping. + // This will work well with UINavigationController, but has an assumption that view controller will - // never be readded as a child view controller. - // It it was readded UI wouldn't be bound anymore. + // never be added as a child view controller. If we didn't recreate the dispose bag here, + // then our resources would never be properly released. override func willMoveToParentViewController(parent: UIViewController?) { if let parent = parent { assert(parent.isKindOfClass(UINavigationController), "Please read comments") diff --git a/RxExample/RxExample/OSX/Main.storyboard b/RxExample/RxExample/OSX/Main.storyboard index d082dd26..06e65af4 100644 --- a/RxExample/RxExample/OSX/Main.storyboard +++ b/RxExample/RxExample/OSX/Main.storyboard @@ -1,7 +1,7 @@ - + - + @@ -52,6 +52,7 @@ + @@ -66,6 +67,7 @@ + @@ -74,6 +76,7 @@ + @@ -82,25 +85,28 @@ + - + + - + @@ -294,14 +318,17 @@ + - - + + + - - + + + @@ -311,21 +338,24 @@ - + + + @@ -336,16 +366,18 @@ - + + @@ -358,6 +390,7 @@ + @@ -398,6 +431,7 @@ + @@ -412,6 +446,7 @@ + @@ -678,6 +743,7 @@ This is only showcase app, not intended for production purposes. + @@ -685,24 +751,29 @@ This is only showcase app, not intended for production purposes. + + + + @@ -711,11 +782,13 @@ This is only showcase app, not intended for production purposes. + @@ -724,6 +797,7 @@ This is only showcase app, not intended for production purposes. + @@ -786,6 +863,7 @@ This is only showcase app, not intended for production purposes. + diff --git a/RxSwift.podspec b/RxSwift.podspec index f2c47df8..6d837274 100644 --- a/RxSwift.podspec +++ b/RxSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "RxSwift" - s.version = "2.0.0-alpha.3" + s.version = "2.0.0-alpha.4" s.summary = "Microsoft Reactive Extensions (Rx) for Swift and iOS/OSX platform" s.description = <<-DESC This is a Swift port of Reactive extensions. @@ -33,6 +33,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' s.watchos.deployment_target = '2.0' + s.tvos.deployment_target = '9.0' s.source_files = 'RxSwift/**/*.swift' end diff --git a/RxSwift/Error.swift b/RxSwift/Error.swift index a907583d..acb7afff 100644 --- a/RxSwift/Error.swift +++ b/RxSwift/Error.swift @@ -22,6 +22,7 @@ public enum RxErrorCode : Int { case Unknown = 0 case Cast = 2 case Disposed = 3 + case Overflow = 4 } /** @@ -42,5 +43,7 @@ public struct RxError { Singleton instance of doing something on a disposed object */ public static let DisposedError = NSError(domain: RxErrorDomain, code: RxErrorCode.Disposed.rawValue, userInfo: nil) + + public static let OverflowError = NSError(domain: RxErrorDomain, code: RxErrorCode.Overflow.rawValue, userInfo: nil) } \ No newline at end of file diff --git a/RxSwift/Observables/Implementations/FlatMap.swift b/RxSwift/Observables/Implementations/FlatMap.swift index 8f21ef7d..7395e01a 100644 --- a/RxSwift/Observables/Implementations/FlatMap.swift +++ b/RxSwift/Observables/Implementations/FlatMap.swift @@ -144,14 +144,15 @@ class FlatMapSink1 : FlatMapSink { - var index = 0 + + private var _index = 0 override init(parent: Parent, observer: O, cancel: Disposable) { super.init(parent: parent, observer: observer, cancel: cancel) } override func performMap(element: SourceType) throws -> S { - return try self.parent.selector2!(element, index++) + return try parent.selector2!(element, try incrementChecked(&_index)) } } diff --git a/RxSwift/Observables/Implementations/Map.swift b/RxSwift/Observables/Implementations/Map.swift index 44a3ef7a..58cba636 100644 --- a/RxSwift/Observables/Implementations/Map.swift +++ b/RxSwift/Observables/Implementations/Map.swift @@ -62,13 +62,13 @@ class MapSink1 : MapSink { class MapSink2 : MapSink { typealias ResultType = O.E - var index = 0 + private var _index = 0 override init(parent: Map, observer: O, cancel: Disposable) { super.init(parent: parent, observer: observer, cancel: cancel) } override func performMap(element: SourceType) throws -> ResultType { - return try self.parent.selector2!(element, index++) + return try self.parent.selector2!(element, try incrementChecked(&_index)) } } diff --git a/RxSwift/Observables/Implementations/Skip.swift b/RxSwift/Observables/Implementations/Skip.swift index 1ed43f17..9c69b9e1 100644 --- a/RxSwift/Observables/Implementations/Skip.swift +++ b/RxSwift/Observables/Implementations/Skip.swift @@ -69,8 +69,6 @@ class SkipTimeSink) { - lock.performLocked { - switch event { - case .Next(let value): - if open { - observer?.on(.Next(value)) - } - case .Error: - observer?.on(event) - self.dispose() - case .Completed: - observer?.on(event) - self.dispose() + switch event { + case .Next(let value): + if open { + observer?.on(.Next(value)) } + case .Error: + observer?.on(event) + self.dispose() + case .Completed: + observer?.on(event) + self.dispose() } } diff --git a/RxSwift/Observables/Implementations/SkipUntil.swift b/RxSwift/Observables/Implementations/SkipUntil.swift new file mode 100644 index 00000000..6ce123ce --- /dev/null +++ b/RxSwift/Observables/Implementations/SkipUntil.swift @@ -0,0 +1,130 @@ +// +// SkipUntil.swift +// Rx +// +// Created by Yury Korolev on 10/3/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +class SkipUntilSinkOther : ObserverType { + typealias Parent = SkipUntilSink + typealias E = Other + + private let _parent: Parent + + private let _singleAssignmentDisposable = SingleAssignmentDisposable() + + var disposable: Disposable { + get { + return abstractMethod() + } + set { + _singleAssignmentDisposable.disposable = newValue + } + } + + init(parent: Parent) { + _parent = parent + #if TRACE_RESOURCES + OSAtomicIncrement32(&resourceCount) + #endif + } + + func on(event: Event) { + switch event { + case .Next: + _parent._lock.performLocked { + _parent._forwardElements = true + _singleAssignmentDisposable.dispose() + } + case .Error(let e): + _parent._lock.performLocked { + _parent.observer?.onError(e) + _parent.dispose() + } + case .Completed: + _singleAssignmentDisposable.dispose() + } + } + + #if TRACE_RESOURCES + deinit { + OSAtomicDecrement32(&resourceCount) + } + #endif + +} + + +class SkipUntilSink : Sink, ObserverType { + typealias E = ElementType + typealias Parent = SkipUntil + + private let _lock = NSRecursiveLock() + private let _parent: Parent + private var _forwardElements = false + + private let _singleAssignmentDisposable = SingleAssignmentDisposable() + + var disposable: Disposable { + get { + return abstractMethod() + } + set { + _singleAssignmentDisposable.disposable = newValue + } + } + + init(parent: Parent, observer: O, cancel: Disposable) { + _parent = parent + super.init(observer: observer, cancel: cancel) + } + + func on(event: Event) { + _lock.performLocked { + switch event { + case .Next: + if _forwardElements { + observer?.on(event) + } + case .Error: + observer?.on(event) + dispose() + case .Completed: + if _forwardElements { + observer?.on(event) + } + _singleAssignmentDisposable.dispose() + } + } + } + + func run() -> Disposable { + let sourceSubscription = _parent._source.subscribeSafe(self) + let otherObserver = SkipUntilSinkOther(parent: self) + let otherSubscription = _parent._other.subscribeSafe(otherObserver) + disposable = sourceSubscription + otherObserver.disposable = otherSubscription + + return BinaryDisposable(sourceSubscription, otherSubscription) + } +} + +class SkipUntil: Producer { + + private let _source: Observable + private let _other: Observable + + init(source: Observable, other: Observable) { + _source = source + _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() + } +} diff --git a/RxSwift/Observables/Implementations/SkipWhile.swift b/RxSwift/Observables/Implementations/SkipWhile.swift new file mode 100644 index 00000000..36942bec --- /dev/null +++ b/RxSwift/Observables/Implementations/SkipWhile.swift @@ -0,0 +1,115 @@ +// +// SkipWhile.swift +// Rx +// +// Created by Yury Korolev on 10/9/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +class SkipWhileSink : Sink, ObserverType { + + typealias Parent = SkipWhile + typealias Element = ElementType + + private let _parent: Parent + private var _running = false + + init(parent: Parent, observer: O, cancel: Disposable) { + _parent = parent + super.init(observer: observer, cancel: cancel) + } + + func on(event: Event) { + switch event { + case .Next(let value): + if !_running { + do { + _running = try !_parent._predicate(value) + } catch let e { + observer?.onError(e) + dispose() + return + } + } + + if _running { + observer?.onNext(value) + } + case .Error, .Completed: + observer?.on(event) + dispose() + } + } +} + +class SkipWhileSinkWithIndex : Sink, ObserverType { + + typealias Parent = SkipWhile + typealias Element = ElementType + + private let _parent: Parent + private var _index = 0 + private var _running = false + + init(parent: Parent, observer: O, cancel: Disposable) { + _parent = parent + super.init(observer: observer, cancel: cancel) + } + + func on(event: Event) { + switch event { + case .Next(let value): + if !_running { + do { + _running = try !_parent._predicateWithIndex(value, _index) + try incrementChecked(&_index) + } catch let e { + observer?.onError(e) + dispose() + return + } + } + + if _running { + observer?.onNext(value) + } + case .Error, .Completed: + observer?.on(event) + dispose() + } + } +} + +class SkipWhile: Producer { + typealias Predicate = (Element) throws -> Bool + typealias PredicateWithIndex = (Element, Int) throws -> Bool + + private let _source: Observable + private let _predicate: Predicate! + private let _predicateWithIndex: PredicateWithIndex! + + init(source: Observable, predicate: Predicate) { + _source = source + _predicate = predicate + _predicateWithIndex = nil + } + + init(source: Observable, predicate: PredicateWithIndex) { + _source = source + _predicate = nil + _predicateWithIndex = predicate + } + + override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + if let _ = _predicate { + let sink = SkipWhileSink(parent: self, observer: observer, cancel: cancel) + setSink(sink) + return _source.subscribeSafe(sink) + } + else { + let sink = SkipWhileSinkWithIndex(parent: self, observer: observer, cancel: cancel) + setSink(sink) + return _source.subscribeSafe(sink) + } + } +} diff --git a/RxSwift/Observables/Implementations/TakeWhile.swift b/RxSwift/Observables/Implementations/TakeWhile.swift index 23164c13..20d4b1e1 100644 --- a/RxSwift/Observables/Implementations/TakeWhile.swift +++ b/RxSwift/Observables/Implementations/TakeWhile.swift @@ -8,118 +8,121 @@ import Foundation -class TakeWhileSink1 : Sink, ObserverType { +class TakeWhileSink : Sink, ObserverType { typealias Parent = TakeWhile typealias Element = ElementType - let parent: Parent + private let _parent: Parent - var running = true + private var _running = true init(parent: Parent, observer: O, cancel: Disposable) { - self.parent = parent + _parent = parent super.init(observer: observer, cancel: cancel) } func on(event: Event) { - if !running { - return - } switch event { case .Next(let value): + if !_running { + return + } - running = self.parent.predicate1(value) - - if running { - observer?.on(.Next(value)) + do { + _running = try _parent._predicate(value) + } catch let e { + observer?.onError(e) + dispose() + return } - else { - observer?.on(.Completed) - self.dispose() + + if _running { + observer?.onNext(value) + } else { + observer?.onComplete() + dispose() } - case .Error: + case .Error, .Completed: observer?.on(event) - self.dispose() - case .Completed: - observer?.on(event) - self.dispose() + dispose() } } } -class TakeWhileSink2 : Sink, ObserverType { +class TakeWhileSinkWithIndex : Sink, ObserverType { typealias Parent = TakeWhile typealias Element = ElementType - let parent: Parent + private let _parent: Parent - var running = true - var index = 0 + private var _running = true + private var _index = 0 init(parent: Parent, observer: O, cancel: Disposable) { - self.parent = parent + _parent = parent super.init(observer: observer, cancel: cancel) } func on(event: Event) { - if !running { - return - } switch event { case .Next(let value): - - running = self.parent.predicate2(value, index) - self.index = index + 1 - - if running { - observer?.on(.Next(value)) + if !_running { + return } - else { - observer?.on(.Completed) - self.dispose() + + do { + _running = try _parent._predicateWithIndex(value, _index) + try incrementChecked(&_index) + } catch let e { + observer?.onError(e) + dispose() + return } - case .Error: + + if _running { + observer?.onNext(value) + } else { + observer?.onComplete() + dispose() + } + case .Error, .Completed: observer?.on(event) - self.dispose() - case .Completed: - observer?.on(event) - self.dispose() + dispose() } } } class TakeWhile: Producer { - typealias Predicate1 = (Element) -> Bool - typealias Predicate2 = (Element, Int) -> Bool + typealias Predicate = (Element) throws -> Bool + typealias PredicateWithIndex = (Element, Int) throws -> Bool - let source: Observable - let predicate1: Predicate1! - let predicate2: Predicate2! + private let _source: Observable + private let _predicate: Predicate! + private let _predicateWithIndex: PredicateWithIndex! - init(source: Observable, predicate: Predicate1) { - self.source = source - self.predicate1 = predicate - self.predicate2 = nil + init(source: Observable, predicate: Predicate) { + _source = source + _predicate = predicate + _predicateWithIndex = nil } - init(source: Observable, predicate: Predicate2) { - self.source = source - self.predicate1 = nil - self.predicate2 = predicate + init(source: Observable, predicate: PredicateWithIndex) { + _source = source + _predicate = nil + _predicateWithIndex = predicate } override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { - if let _ = self.predicate1 { - let sink = TakeWhileSink1(parent: self, observer: observer, cancel: cancel) + if let _ = _predicate { + let sink = TakeWhileSink(parent: self, observer: observer, cancel: cancel) setSink(sink) - return source.subscribeSafe(sink) - } - else { - let sink = TakeWhileSink2(parent: self, observer: observer, cancel: cancel) + return _source.subscribeSafe(sink) + } else { + let sink = TakeWhileSinkWithIndex(parent: self, observer: observer, cancel: cancel) setSink(sink) - return source.subscribeSafe(sink) + return _source.subscribeSafe(sink) } } } \ No newline at end of file diff --git a/RxSwift/Observables/Observable+Multiple.swift b/RxSwift/Observables/Observable+Multiple.swift index ccf30b25..d9829dda 100644 --- a/RxSwift/Observables/Observable+Multiple.swift +++ b/RxSwift/Observables/Observable+Multiple.swift @@ -165,6 +165,22 @@ extension ObservableType { } } +// skipUntil + +extension ObservableType { + + /** + Returns the elements from the source observable sequence until the other observable sequence produces an element. + + - parameter other: Observable sequence that terminates propagation of elements of the source sequence. + - returns: An observable sequence containing the elements of the source sequence up to the point the other sequence interrupted further propagation. + */ + public func skipUntil(other: O) + -> Observable { + return SkipUntil(source: self.asObservable(), other: other.asObservable()) + } +} + // amb extension ObservableType { diff --git a/RxSwift/Observables/Observable+StandardSequenceOperators.swift b/RxSwift/Observables/Observable+StandardSequenceOperators.swift index 021f6c65..8a12aeb5 100644 --- a/RxSwift/Observables/Observable+StandardSequenceOperators.swift +++ b/RxSwift/Observables/Observable+StandardSequenceOperators.swift @@ -34,9 +34,9 @@ extension ObservableType { - parameter predicate: A function to test each element for a condition. - returns: An observable sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes. */ - public func takeWhile(predicate: (E) -> Bool) + public func takeWhile(predicate: (E) throws -> Bool) -> Observable { - return TakeWhile(source: self.asObservable(), predicate: predicate) + return TakeWhile(source: asObservable(), predicate: predicate) } /** @@ -47,9 +47,9 @@ extension ObservableType { - parameter predicate: A function to test each element for a condition; the second parameter of the function represents the index of the source element. - returns: An observable sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes. */ - public func takeWhile(predicate: (E, Int) -> Bool) + public func takeWhileWithIndex(predicate: (E, Int) throws -> Bool) -> Observable { - return TakeWhile(source: self.asObservable(), predicate: predicate) + return TakeWhile(source: asObservable(), predicate: predicate) } } @@ -90,6 +90,32 @@ extension ObservableType { } } +// SkipWhile + +extension ObservableType { + + /** + Bypasses elements in an observable sequence as long as a specified condition is true and then returns the remaining elements. + + - parameter predicate: A function to test each element for a condition. + - returns: An observable sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate. + */ + public func skipWhile(predicate: (E) throws -> Bool) -> Observable { + return SkipWhile(source: self.asObservable(), predicate: predicate) + } + + /** + Bypasses elements in an observable sequence as long as a specified condition is true and then returns the remaining elements. + The element's index is used in the logic of the predicate function. + + - parameter predicate: A function to test each element for a condition; the second parameter of the function represents the index of the source element. + - returns: An observable sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate. + */ + public func skipWhileWithIndex(predicate: (E, Int) throws -> Bool) -> Observable { + return SkipWhile(source: self.asObservable(), predicate: predicate) + } +} + // map aka select extension ObservableType { diff --git a/RxSwift/Observables/Observable+Time.swift b/RxSwift/Observables/Observable+Time.swift index b086b8c6..a0c6f897 100644 --- a/RxSwift/Observables/Observable+Time.swift +++ b/RxSwift/Observables/Observable+Time.swift @@ -197,4 +197,4 @@ extension ObservableType { -> Observable<[E]> { return BufferTimeCount(source: self.asObservable(), timeSpan: timeSpan, count: count, scheduler: scheduler) } -} \ No newline at end of file +} diff --git a/RxSwift/Rx.swift b/RxSwift/Rx.swift index 1362e196..64c1f6d7 100644 --- a/RxSwift/Rx.swift +++ b/RxSwift/Rx.swift @@ -30,6 +30,15 @@ func rxFatalError(lastMessage: String) { fatalError(lastMessage) } +func incrementChecked(inout i: Int) throws -> Int { + if i == Int.max { + throw RxError.OverflowError + } + let result = i + i += 1 + return result +} + extension NSObject { func rx_synchronized(@noescape action: () -> T) -> T { objc_sync_enter(self) diff --git a/RxTests/RxCocoaTests/KVOObservableTests.swift b/RxTests/RxCocoaTests/KVOObservableTests.swift index 6dd2cc37..4ee76757 100644 --- a/RxTests/RxCocoaTests/KVOObservableTests.swift +++ b/RxTests/RxCocoaTests/KVOObservableTests.swift @@ -208,7 +208,7 @@ extension KVOObservableTests { latest = n } - parent.rx_deallocated + _ = parent.rx_deallocated .subscribeCompleted { disposed = true } @@ -235,7 +235,7 @@ extension KVOObservableTests { latest = n } - parent.rx_deallocated + _ = parent.rx_deallocated .subscribeCompleted { disposed = true } @@ -266,12 +266,12 @@ extension KVOObservableTests { var root: HasStrongProperty! = HasStrongProperty() - root.rx_observeWeakly("property") + _ = root.rx_observeWeakly("property") .subscribeNext { (n: String?) in latest = n } - root.rx_deallocated + _ = root.rx_deallocated .subscribeCompleted { disposed = true } @@ -296,12 +296,12 @@ extension KVOObservableTests { var root: HasWeakProperty! = HasWeakProperty() - root.rx_observeWeakly("property") + _ = root.rx_observeWeakly("property") .subscribeNext { (n: String?) in latest = n } - root.rx_deallocated + _ = root.rx_deallocated .subscribeCompleted { disposed = true } @@ -330,12 +330,12 @@ extension KVOObservableTests { var root: HasWeakProperty! = HasWeakProperty() - root.rx_observeWeakly("property.property") + _ = root.rx_observeWeakly("property.property") .subscribeNext { (n: String?) in latest = n } - root.rx_deallocated + _ = root.rx_deallocated .subscribeCompleted { disposed = true } @@ -379,12 +379,12 @@ extension KVOObservableTests { XCTAssertTrue(latest == nil) XCTAssertTrue(disposed == false) - root.rx_observeWeakly("property.property") + _ = root.rx_observeWeakly("property.property") .subscribeNext { (n: String?) in latest = n } - root.rx_deallocated + _ = root.rx_deallocated .subscribeCompleted { disposed = true } @@ -407,12 +407,12 @@ extension KVOObservableTests { var root: HasStrongProperty! = HasStrongProperty() - root.rx_observeWeakly("property.property") + _ = root.rx_observeWeakly("property.property") .subscribeNext { (n: String?) in latest = n } - root.rx_deallocated + _ = root.rx_deallocated .subscribeCompleted { disposed = true } @@ -456,12 +456,12 @@ extension KVOObservableTests { XCTAssertTrue(latest == nil) XCTAssertTrue(disposed == false) - root.rx_observeWeakly("property.property") + _ = root.rx_observeWeakly("property.property") .subscribeNext { (n: String?) in latest = n } - root.rx_deallocated + _ = root.rx_deallocated .subscribeCompleted { disposed = true } @@ -496,9 +496,10 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) let observable: Observable = root.rx_observeWeakly("property.property") - observable .subscribeNext { n in - latest?.value = n - } + _ = observable + .subscribeNext { n in + latest?.value = n + } XCTAssertTrue(latest.value! === one) @@ -512,7 +513,7 @@ extension KVOObservableTests { func testObserveWeak_Strong_Weak_Observe_NilLastPropertyBecauseOfWeak() { var gone = false let (child, latest, dealloc) = _testObserveWeak_Strong_Weak_Observe_NilLastPropertyBecauseOfWeak() - dealloc + _ = dealloc .subscribeNext { n in gone = true } @@ -538,9 +539,10 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) let observable: Observable = root.rx_observeWeakly("property.property.property") - observable .subscribeNext { n in - latest?.value = n - } + _ = observable + .subscribeNext { n in + latest?.value = n + } XCTAssertTrue(latest.value == nil) @@ -560,7 +562,7 @@ extension KVOObservableTests { var gone = false - deallocatedMiddle + _ = deallocatedMiddle .subscribeCompleted { gone = true } @@ -579,7 +581,8 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) - root.rx_observeWeakly("property") + _ = root + .rx_observeWeakly("property") .subscribeNext { (n: String?) in latest.value = n } @@ -588,7 +591,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -608,10 +612,11 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) - root.rx_observeWeakly("property", options: .New) + _ = root + .rx_observeWeakly("property", options: .New) .subscribeNext { (n: String?) in latest.value = n - } + } XCTAssertTrue(latest.value == nil) @@ -621,10 +626,11 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true - } + } root = nil @@ -653,7 +659,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -693,10 +700,11 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true - } + } root = nil @@ -728,7 +736,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -763,7 +772,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -797,7 +807,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -816,7 +827,8 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) - root.rx_observeWeakly("frame") + _ = root + .rx_observeWeakly("frame") .subscribeNext { (n: CGRect?) in latest.value = n } @@ -828,7 +840,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -846,7 +859,8 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) - root.rx_observeWeakly("size") + _ = root + .rx_observeWeakly("size") .subscribeNext { (n: CGSize?) in latest.value = n } @@ -858,10 +872,11 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true - } + } root = nil @@ -876,7 +891,8 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) - root.rx_observeWeakly("point") + _ = root + .rx_observeWeakly("point") .subscribeNext { (n: CGPoint?) in latest.value = n } @@ -889,7 +905,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -907,7 +924,8 @@ extension KVOObservableTests { XCTAssertTrue(latest.value == nil) - root.rx_observeWeakly("integer") + _ = root + .rx_observeWeakly("integer") .subscribeNext { (n: NSNumber?) in latest.value = n?.integerValue } @@ -919,10 +937,11 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true - } + } root = nil @@ -935,7 +954,7 @@ extension KVOObservableTests { var lastError: ErrorType? = nil - (root.rx_observeWeakly("notExist") as Observable) + _ = (root.rx_observeWeakly("notExist") as Observable) .subscribeError { error in lastError = error } @@ -944,7 +963,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } @@ -959,7 +979,7 @@ extension KVOObservableTests { var lastError: ErrorType? = nil - (root.rx_observeWeakly("property.notExist") as Observable) + _ = (root.rx_observeWeakly("property.notExist") as Observable) .subscribeError { error in lastError = error } @@ -972,7 +992,8 @@ extension KVOObservableTests { var rootDeallocated = false - root.rx_deallocated + _ = root + .rx_deallocated .subscribeCompleted { rootDeallocated = true } diff --git a/RxTests/RxCocoaTests/NSObject+RxTests.swift b/RxTests/RxCocoaTests/NSObject+RxTests.swift index 701b6508..912efe88 100644 --- a/RxTests/RxCocoaTests/NSObject+RxTests.swift +++ b/RxTests/RxCocoaTests/NSObject+RxTests.swift @@ -22,7 +22,8 @@ extension NSObjectTests { var fired = false - a.rx_deallocated + _ = a + .rx_deallocated .map { _ in return 1 } @@ -42,7 +43,8 @@ extension NSObjectTests { var fired = false - a.rx_deallocated + _ = a + .rx_deallocated .map { _ in return 1 } @@ -62,7 +64,8 @@ extension NSObjectTests { var fired = false - a.rx_deallocated + _ = a + .rx_deallocated .map { _ in return 1 } @@ -87,7 +90,8 @@ extension NSObjectTests { var fired = false - a.rx_deallocating + _ = a + .rx_deallocating .map { _ in return 1 } @@ -107,7 +111,8 @@ extension NSObjectTests { var fired = false - a.rx_deallocating + _ = a + .rx_deallocating .map { _ in return 1 } @@ -127,7 +132,8 @@ extension NSObjectTests { var fired = false - a.rx_deallocating + _ = a + .rx_deallocating .map { _ in return 1 } diff --git a/RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift b/RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift index bd827600..4e5b8fe4 100644 --- a/RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift +++ b/RxTests/RxSwiftTests/Tests/AnonymousObservable+Test.swift @@ -48,7 +48,7 @@ extension AnonymousObservableTests { var elements = [Int]() - a.subscribeNext { n in + _ = a.subscribeNext { n in elements.append(n) } @@ -71,8 +71,8 @@ extension AnonymousObservableTests { } as Observable var elements = [Int]() - - a.subscribeNext { n in + + _ = a.subscribeNext { n in elements.append(n) } diff --git a/RxTests/RxSwiftTests/Tests/AssumptionsTest.swift b/RxTests/RxSwiftTests/Tests/AssumptionsTest.swift index 7ebfc2e9..14741ca8 100644 --- a/RxTests/RxSwiftTests/Tests/AssumptionsTest.swift +++ b/RxTests/RxSwiftTests/Tests/AssumptionsTest.swift @@ -65,12 +65,12 @@ class AssumptionsTest : RxTest { } func testFunctionReturnValueOverload() { - returnSomething() + _ = returnSomething() .subscribeNext { (n: AnyObject?) in XCTAssertEqual("\(n ?? NSNull())", "a") } - returnSomething() + _ = returnSomething() .subscribeNext { (n: CGRect?) in XCTAssertEqual(n!, CGRectMake(0, 0, 100, 100)) } diff --git a/RxTests/RxSwiftTests/Tests/DelegateProxyTest.swift b/RxTests/RxSwiftTests/Tests/DelegateProxyTest.swift index d577656a..358ff480 100644 --- a/RxTests/RxSwiftTests/Tests/DelegateProxyTest.swift +++ b/RxTests/RxSwiftTests/Tests/DelegateProxyTest.swift @@ -240,7 +240,9 @@ class DelegateProxyTest : RxTest { let sentArgument = NSIndexPath(index: 0) - view.rx_proxy.observe("threeDView:didGetXXX:") + _ = view + .rx_proxy + .observe("threeDView:didGetXXX:") .subscribeCompleted { completed.value = true } diff --git a/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift b/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift index 01e512cb..1809ca45 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift @@ -169,7 +169,7 @@ extension ObservableBindingTest { let xs: Observable = failWith(testError) let res = xs.publish().refCount() - res.subscribe { event in + _ = res.subscribe { event in switch event { case .Next: XCTAssertTrue(false) @@ -179,7 +179,7 @@ extension ObservableBindingTest { XCTAssertTrue(false) } } - res.subscribe { event in + _ = res.subscribe { event in switch event { case .Next: XCTAssertTrue(false) @@ -266,7 +266,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable = sequenceOf(0, 1, 2).replay(3).refCount() - observable.subscribeNext { n in + _ = observable.subscribeNext { n in nEvents++ } @@ -277,7 +277,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable = [sequenceOf(0, 1, 2), failWith(testError)].concat().replay(3).refCount() - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -288,7 +288,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable: Observable = failWith(testError).replay(3).refCount() - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -299,7 +299,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable: Observable = empty().replay(3).refCount() - observable.subscribeCompleted { + _ = observable.subscribeCompleted { nEvents++ } @@ -310,7 +310,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable = sequenceOf(0, 1, 2).replay(1).refCount() - observable.subscribeNext { n in + _ = observable.subscribeNext { n in nEvents++ } @@ -321,7 +321,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable = [just(0, 1, 2), failWith(testError)].concat().replay(1).refCount() - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -332,7 +332,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable: Observable = failWith(testError).replay(1).refCount() - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -343,7 +343,7 @@ extension ObservableBindingTest { var nEvents = 0 let observable: Observable = empty().replay(1).refCount() - observable.subscribeCompleted { + _ = observable.subscribeCompleted { nEvents++ } diff --git a/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift b/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift index 8677b858..a042c81b 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift @@ -86,7 +86,7 @@ extension ObservableCreationTests { var elements = [Int]() - generate(0, condition: { _ in true }) { x in + _ = generate(0, condition: { _ in true }) { x in count++ return x + 1 } diff --git a/RxTests/RxSwiftTests/Tests/Observable+MultipleTest.swift b/RxTests/RxSwiftTests/Tests/Observable+MultipleTest.swift index 8e36ad59..7de57089 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+MultipleTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+MultipleTest.swift @@ -621,7 +621,7 @@ extension ObservableMultipleTest { extension ObservableMultipleTest { func testConcat_DefaultScheduler() { var sum = 0 - [just(1), just(2), just(3)].concat().subscribeNext { (e) -> Void in + _ = [just(1), just(2), just(3)].concat().subscribeNext { (e) -> Void in sum += e } @@ -1217,7 +1217,7 @@ extension ObservableMultipleTest { sequenceOf(0, 1, 2) ).merge() - observable.subscribeNext { n in + _ = observable.subscribeNext { n in nEvents++ } @@ -1233,7 +1233,7 @@ extension ObservableMultipleTest { sequenceOf(0, 1, 2) ).merge() - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -1247,7 +1247,7 @@ extension ObservableMultipleTest { failWith(testError) ).merge() - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -1258,7 +1258,7 @@ extension ObservableMultipleTest { var nEvents = 0 let observable: Observable = (empty() as Observable>).merge() - observable.subscribeCompleted { + _ = observable.subscribeCompleted { nEvents++ } @@ -1269,7 +1269,7 @@ extension ObservableMultipleTest { var nEvents = 0 let observable: Observable = just(empty()).merge() - observable.subscribeCompleted { n in + _ = observable.subscribeCompleted { n in nEvents++ } @@ -1285,7 +1285,7 @@ extension ObservableMultipleTest { sequenceOf(0, 1, 2) ).merge(maxConcurrent: 1) - observable.subscribeNext { n in + _ = observable.subscribeNext { n in nEvents++ } @@ -1301,7 +1301,7 @@ extension ObservableMultipleTest { sequenceOf(0, 1, 2) ).merge(maxConcurrent: 1) - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -1315,7 +1315,7 @@ extension ObservableMultipleTest { failWith(testError) ).merge(maxConcurrent: 1) - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -1327,7 +1327,7 @@ extension ObservableMultipleTest { let observable: Observable = (empty() as Observable>).merge(maxConcurrent: 1) - observable.subscribeCompleted { + _ = observable.subscribeCompleted { nEvents++ } @@ -1339,7 +1339,7 @@ extension ObservableMultipleTest { let observable: Observable = just(empty()).merge(maxConcurrent: 1) - observable.subscribeCompleted { n in + _ = observable.subscribeCompleted { n in nEvents++ } @@ -2160,7 +2160,7 @@ extension ObservableMultipleTest { var nEvents = 0 let observable = combineLatest(sequenceOf(0, 1, 2), sequenceOf(0, 1, 2)) { $0 + $1 } - observable.subscribeNext { n in + _ = observable.subscribeNext { n in nEvents++ } @@ -2175,7 +2175,7 @@ extension ObservableMultipleTest { sequenceOf(0, 1, 2) ) { $0 + $1 } - observable.subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -2190,7 +2190,7 @@ extension ObservableMultipleTest { sequenceOf(0, 1, 2) ) { $0 + $1 } - observable .subscribeError { n in + _ = observable.subscribeError { n in nEvents++ } @@ -2206,7 +2206,7 @@ extension ObservableMultipleTest { sequenceOf(0, 1, 2) ) { $0 + $1 } - observable.subscribeCompleted { + _ = observable.subscribeCompleted { nEvents++ } @@ -3597,4 +3597,355 @@ extension ObservableMultipleTest { XCTAssertEqual(e2.subscriptions, [Subscription(200, 230)]) XCTAssertEqual(e3.subscriptions, [Subscription(200, 230)]) } +} + + +// MARK: skipUntil + +extension ObservableMultipleTest { + func testSkipUntil_SomeData_Next() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + next(210, 2), + next(220, 3), + next(230, 4), //! + next(240, 5), //! + completed(250) + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + next(225, 99), + completed(230) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + next(230, 4), + next(240, 5), + completed(250) + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 250) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 225) + ]) + } + + func testSkipUntil_SomeData_Error() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + next(210, 2), + next(220, 3), + next(230, 4), + next(240, 5), + completed(250) + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + error(225, testError) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + error(225, testError), + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 225) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 225) + ]) + } + + func testSkipUntil_Error_SomeData() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + next(210, 2), + error(220, testError) + + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + next(230, 2), + completed(250) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + error(220, testError), + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 220) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 220) + ]) + } + + func testSkipUntil_SomeData_Empty() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + next(210, 2), + next(220, 3), + next(230, 4), + next(240, 5), + completed(250) + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + completed(225) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 250) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 225) + ]) + } + + func testSkipUntil_Never_Next() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1) + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + next(225, 2), //! + completed(250) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 1000) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 225) + ]) + } + + func testSkipUntil_Never_Error1() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1) + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + error(225, testError) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + error(225, testError) + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 225) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 225) + ]) + } + + func testSkipUntil_SomeData_Error2() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + next(210, 2), + next(220, 3), + next(230, 4), + next(240, 5), + completed(250) + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + error(300, testError) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + error(300, testError) + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 250) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 300) + ]) + } + + func testSkipUntil_SomeData_Never() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + next(210, 2), + next(220, 3), + next(230, 4), + next(240, 5), + completed(250) + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 250) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 1000) + ]) + } + + func testSkipUntil_Never_Empty() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + completed(225) + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 1000) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 225) + ]) + } + + func testSkipUntil_Never_Never() { + let scheduler = TestScheduler(initialClock: 0) + + let l = scheduler.createHotObservable([ + next(150, 1), + ]) + + let r = scheduler.createHotObservable([ + next(150, 1), + ]) + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + ]) + + XCTAssertEqual(l.subscriptions, [ + Subscription(200, 1000) + ]) + + XCTAssertEqual(r.subscriptions, [ + Subscription(200, 1000) + ]) + } + + func testSkipUntil_HasCompletedCausesDisposal() { + let scheduler = TestScheduler(initialClock: 0) + + var disposed = false + + let l = scheduler.createHotObservable([ + next(150, 1), + next(210, 2), + next(220, 3), + next(230, 4), + next(240, 5), + completed(250) + ]) + + let r: Observable = create { o in + return AnonymousDisposable { + disposed = true + } + } + + let res = scheduler.start { + l.skipUntil(r) + } + + XCTAssertEqual(res.messages, [ + ]) + + XCTAssert(disposed, "disposed") + } } \ No newline at end of file diff --git a/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift b/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift index a106c747..83194fc5 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+StandardSequenceOperatorsTest.swift @@ -504,6 +504,51 @@ extension ObservableStandardSequenceOperators { XCTAssertEqual(1, invoked) } + func testTakeWhile_Throw() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + var invoked = 0 + + let res = scheduler.start() { () -> Observable in + return xs.takeWhile { num in + invoked++ + + if invoked == 3 { + throw testError + } + + return isPrime(num) + } + } + + XCTAssertEqual(res.messages, [ + next(210, 2), + next(260, 5), + error(290, testError) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 290) + ]) + + XCTAssertEqual(3, invoked) + } + func testTakeWhile_Index1() { let scheduler = TestScheduler(initialClock: 0) @@ -524,9 +569,7 @@ extension ObservableStandardSequenceOperators { ]) let res = scheduler.start { () -> Observable in - return xs.takeWhile { (num: Int, index) -> Bool in - return index < 5 - } + return xs.takeWhileWithIndex { num, index in index < 5 } } XCTAssertEqual(res.messages, [ @@ -560,9 +603,7 @@ extension ObservableStandardSequenceOperators { ]) let res = scheduler.start { () -> Observable in - return xs.takeWhile { (num: Int, index) -> Bool in - return index >= 0 - } + return xs.takeWhileWithIndex { num , index in return index >= 0 } } XCTAssertEqual(res.messages, [ @@ -598,9 +639,7 @@ extension ObservableStandardSequenceOperators { ]) let res = scheduler.start { () -> Observable in - return xs.takeWhile { (num: Int, index) -> Bool in - return index >= 0 - } + return xs.takeWhileWithIndex { num, index in index >= 0 } } XCTAssertEqual(res.messages, [ @@ -618,6 +657,48 @@ extension ObservableStandardSequenceOperators { Subscription(200, 400) ]) } + + + func testTakeWhile_Index_SelectorThrows() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(205, 100), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + completed(400) + ]) + + let res = scheduler.start { () -> Observable in + return xs.takeWhileWithIndex { num, index in + if index < 5 { + return true + } + + throw testError + } + } + + XCTAssertEqual(res.messages, [ + next(205, 100), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + error(350, testError) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 350) + ]) + } + } // map @@ -942,7 +1023,7 @@ extension ObservableStandardSequenceOperators { } func testMap_DisposeOnCompleted() { - just("A") + _ = just("A") .map { a in return a } @@ -952,7 +1033,7 @@ extension ObservableStandardSequenceOperators { } func testMap1_DisposeOnCompleted() { - just("A") + _ = just("A") .mapWithIndex { (a, i) in return a } @@ -2730,7 +2811,7 @@ extension ObservableStandardSequenceOperators { func testTake_DecrementCountsFirst() { let k = BehaviorSubject(value: false) - k.take(1).subscribeNext { n in + _ = k.take(1).subscribeNext { n in k.on(.Next(!n)) } } @@ -3128,4 +3209,439 @@ extension ObservableStandardSequenceOperators { Subscription(200, 400) ]) } +} + +// MARK: SkipWhile +extension ObservableStandardSequenceOperators { + + func testSkipWhile_Complete_Before() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + completed(330), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + var invoked = 0 + + let res = scheduler.start() { + xs.skipWhile { x in + invoked += 1 + return isPrime(x) + } + } + + XCTAssertEqual(res.messages, [ + completed(330) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 330) + ]) + + XCTAssertEqual(4, invoked) + } + + func testSkipWhile_Complete_After() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + var invoked = 0 + + let res = scheduler.start() { + xs.skipWhile { x in + invoked += 1 + return isPrime(x) + } + } + + XCTAssertEqual(res.messages, [ + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 600) + ]) + + XCTAssertEqual(6, invoked) + } + + func testSkipWhile_Error_Before() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + error(270, testError), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23) + ]) + + var invoked = 0 + + let res = scheduler.start() { + xs.skipWhile { x in + invoked += 1 + return isPrime(x) + } + } + + + + XCTAssertEqual(res.messages, [ + error(270, testError) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 270) + ]) + + XCTAssertEqual(2, invoked) + } + + func testSkipWhile_Error_After() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + error(600, testError) + ]) + + var invoked = 0 + + let res = scheduler.start() { + xs.skipWhile { x in + invoked += 1 + return isPrime(x) + } + } + + XCTAssertEqual(res.messages, [ + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + error(600, testError) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 600) + ]) + + XCTAssertEqual(6, invoked) + } + + func testSkipWhile_Dispose_Before() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + var invoked = 0 + + let res = scheduler.start(300) { + xs.skipWhile { x in + invoked += 1 + return isPrime(x) + } + } + + XCTAssertEqual(res.messages, []) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 300) + ]) + + XCTAssertEqual(3, invoked) + } + + func testSkipWhile_Dispose_After() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + var invoked = 0 + + let res = scheduler.start(470) { + xs.skipWhile { x in + invoked += 1 + return isPrime(x) + } + } + + XCTAssertEqual(res.messages, [ + next(390, 4), + next(410, 17), + next(450, 8) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 470) + ]) + + XCTAssertEqual(6, invoked) + } + + func testSkipWhile_Zero() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(205, 100), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + var invoked = 0 + + let res = scheduler.start() { + xs.skipWhile { x in + invoked += 1 + return isPrime(x) + } + } + + XCTAssertEqual(res.messages, [ + next(205, 100), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 600) + ]) + + XCTAssertEqual(1, invoked) + } + + func testSkipWhile_Throw() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + var invoked = 0 + + let res = scheduler.start() { + xs.skipWhile { x in + invoked += 1 + if invoked == 3 { + throw testError + } + return isPrime(x) + } + } + + XCTAssertEqual(res.messages, [ + error(290, testError) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 290) + ]) + + XCTAssertEqual(3, invoked) + } + + func testSkipWhile_Index() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(205, 100), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + let res = scheduler.start() { + xs.skipWhileWithIndex { x, i in i < 5 } + } + + XCTAssertEqual(res.messages, [ + next(350, 7), + next(390, 4), + next(410, 17), + next(450, 8), + next(500, 23), + completed(600) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 600) + ]) + } + + func testSkipWhile_Index_Throw() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(205, 100), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + error(400, testError) + ]) + + let res = scheduler.start() { + xs.skipWhileWithIndex { x, i in i < 5 } + } + + XCTAssertEqual(res.messages, [ + next(350, 7), + next(390, 4), + error(400, testError) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 400) + ]) + } + + func testSkipWhile_Index_SelectorThrows() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(90, -1), + next(110, -1), + next(205, 100), + next(210, 2), + next(260, 5), + next(290, 13), + next(320, 3), + next(350, 7), + next(390, 4), + completed(400) + ]) + + let res = scheduler.start() { + xs.skipWhileWithIndex { x, i in + if i < 5 { + return true + } + throw testError + } + } + + XCTAssertEqual(res.messages, [ + error(350, testError) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(200, 350) + ]) + } } \ No newline at end of file diff --git a/RxTests/RxSwiftTests/Tests/Observable+TimeTest.swift b/RxTests/RxSwiftTests/Tests/Observable+TimeTest.swift index 15a043b5..eae22e2d 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+TimeTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+TimeTest.swift @@ -957,7 +957,7 @@ extension ObservableTimeTest { ]) let res = scheduler.start { - xs.take(35, scheduler) + xs.take(55, scheduler).take(35, scheduler) } XCTAssertEqual(res.messages, [ @@ -1303,4 +1303,5 @@ extension ObservableTimeTest { XCTAssertEqual(result!, [4, 5, 6]) } + } \ No newline at end of file diff --git a/RxTests/RxSwiftTests/Tests/ObserverTests.swift b/RxTests/RxSwiftTests/Tests/ObserverTests.swift index 0a4ca93b..f3da5516 100644 --- a/RxTests/RxSwiftTests/Tests/ObserverTests.swift +++ b/RxTests/RxSwiftTests/Tests/ObserverTests.swift @@ -22,7 +22,7 @@ extension ObserverTests { var elements = [Int]() - a.subscribeNext { n in + _ = a.subscribeNext { n in elements.append(n) } @@ -43,7 +43,7 @@ extension ObserverTests { var elements = [Int]() var errrorNotification: NSError! - a.subscribe( + _ = a.subscribe( next: { n in elements.append(n) }, error: { e in errrorNotification = e as NSError @@ -71,7 +71,7 @@ extension ObserverTests { var elements = [Int]() - a.subscribeNext { n in + _ = a.subscribeNext { n in elements.append(n) } diff --git a/scripts/automation-tests.sh b/scripts/automation-tests.sh index a1ced3e0..105fc690 100755 --- a/scripts/automation-tests.sh +++ b/scripts/automation-tests.sh @@ -5,7 +5,7 @@ NUM_OF_TESTS=14 CURRENT_DIR="$( dirname "${BASH_SOURCE[0]}" )" BUILD_DIRECTORY=build APP=RxExample -CONFIGURATIONS="Debug Release-Tests Release" +CONFIGURATIONS=(Debug Release-Tests Release) . scripts/common.sh @@ -43,11 +43,20 @@ function runAutomation() { xcrun instruments -w ${SIMULATOR} > /dev/null 2>&1 || echo echo - APP_PATH="${BUILD_DIRECTORY}/Build/Products/${CONFIGURATION}-iphonesimulator/${APP}.app" - printf "${GREEN}Installing the app ${BOLDCYAN}'${APP_PATH}'${GREEN} ...${RESET}\n" + if is_real_device "${SIMULATOR}"; then + OUTPUT_DIR=${CONFIGURATION}-iphoneos + else + OUTPUT_DIR=${CONFIGURATION}-iphonesimulator + fi + APP_PATH="${BUILD_DIRECTORY}/Build/Products/${OUTPUT_DIR}/${APP}.app" + printf "${GREEN}Installing the app ${BOLDCYAN}'${APP_PATH}'${GREEN} (${CONFIGURATION}) ${RESET}...\n" echo - xcrun simctl install ${SIMULATOR} "${APP_PATH}" + if is_real_device "${SIMULATOR}"; then + /Users/kzaher/Projects/ios-deploy/ios-deploy --bundle "${APP_PATH}" + else + xcrun simctl install ${SIMULATOR} "${APP_PATH}" + fi pushd $TMPDIR rm -rf instrumentscli0.trace || echo @@ -56,7 +65,7 @@ function runAutomation() { echo OUTPUT="${TMPDIR}/output.txt" - instruments -w ${SIMULATOR} -t Automation "${APP_PATH}" -e UIASCRIPT "${ROOT}/scripts/automation-tests/main.js" | tee "${OUTPUT}" #| grep "Pass" #|| (open instrumentscli0.trace; exit -1;) + instruments -w "${SIMULATOR}" -t Automation "${APP_PATH}" -e UIASCRIPT "${ROOT}/scripts/automation-tests/main.js" | tee "${OUTPUT}" #| grep "Pass" #|| (open instrumentscli0.trace; exit -1;) COUNT=`grep Pass: "$TMPDIR/output.txt" | wc -l` if [ "$COUNT" -lt "$NUM_OF_TESTS" ]; then @@ -69,23 +78,18 @@ function runAutomation() { echo open ./instrumentscli0.trace; exit -1; + else + printf "${GREEN}Automation says ok on ${BOLDCYAN}${SIMULATOR} - ${CONFIGURATION}${RESET}\n" fi popd } -# ios 7 -#for simulator in ${IOS7_SIMULATORS} -#do -# for configuration in ${CONFIGURATIONS} -# do -# runAutomation "RxExample-iOS" ${configuration} ${simulator} -# done -#done +AUTOMATION_SIMULATORS=("Krunoslav Zaher’s iPhone" ${DEFAULT_IOS9_SIMULATOR} ${DEFAULT_IOS8_SIMULATOR}) -# ios 8 -for simulator in ${IOS8_SIMULATORS} +IFS="" +for simulator in ${AUTOMATION_SIMULATORS[@]} do - for configuration in ${CONFIGURATIONS} + for configuration in ${CONFIGURATIONS[@]} do runAutomation "RxExample-iOS" ${configuration} ${simulator} done diff --git a/scripts/automation-tests/01_githubSignUp.js b/scripts/automation-tests/01_githubSignUp.js index b6f5d848..de1c3200 100644 --- a/scripts/automation-tests/01_githubSignUp.js +++ b/scripts/automation-tests/01_githubSignUp.js @@ -2,39 +2,31 @@ test("----- githubSignUp -----", function (check, pass) { + var target = UIATarget.localTarget(); + UIATarget.onAlert = function(alert){ - UIATarget.localTarget().frontMostApp().alert().buttons()["Cancel"].tap(); + var okButton = UIATarget.localTarget().frontMostApp().alert().buttons()["OK"]; + okButton.tap(); + UIATarget.localTarget().frontMostApp().navigationBar().leftButton().tap(); pass() return false; } - UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[0].tap(); + target.frontMostApp().mainWindow().tableViews()[0].cells()[0].tap(); - UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0].tap(); - writeInElement(UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0], "rxrevolution") + target.frontMostApp().mainWindow().textFields()[0].tap(); + writeInElement(target.frontMostApp().mainWindow().textFields()[0], "rxrevolution") - UIATarget.localTarget().frontMostApp().mainWindow().secureTextFields()[0].tap(); - writeInElement(UIATarget.localTarget().frontMostApp().mainWindow().secureTextFields()[0], "mypassword") + target.frontMostApp().mainWindow().secureTextFields()[0].tap(); + writeInElement(target.frontMostApp().mainWindow().secureTextFields()[0], "mypassword") - UIATarget.localTarget().frontMostApp().mainWindow().secureTextFields()[1].tap(); - writeInElement(UIATarget.localTarget().frontMostApp().mainWindow().secureTextFields()[1], "mypassword") + target.frontMostApp().mainWindow().secureTextFields()[1].tap(); + writeInElement(target.frontMostApp().mainWindow().secureTextFields()[1], "mypassword") UIATarget.localTarget().tap({x:14.50, y:80.00}); - UIATarget.localTarget().frontMostApp().mainWindow().buttons()["Sign up"].tap(); + target.frontMostApp().mainWindow().buttons()["Sign up"].tap(); }); - - - - - - - - - - - - diff --git a/scripts/automation-tests/02_searchWikipedia.js b/scripts/automation-tests/02_searchWikipedia.js index 95aed62c..cff76abf 100644 --- a/scripts/automation-tests/02_searchWikipedia.js +++ b/scripts/automation-tests/02_searchWikipedia.js @@ -2,35 +2,34 @@ test("----- searchWikipedia -----", function (check, pass) { - var width = UIATarget.localTarget().frontMostApp().mainWindow().rect().size.width + var target = UIATarget.localTarget() - UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[3].tap(); + var width = target.frontMostApp().mainWindow().rect().size.width - UIATarget.localTarget().frontMostApp().mainWindow().searchBars()[0].searchBars()[0].tap(); - writeInElement(UIATarget.localTarget().frontMostApp().mainWindow().searchBars()[0].searchBars()[0], "banana") - UIATarget.localTarget().delay(2); + target.frontMostApp().mainWindow().tableViews()[0].cells()[3].tap(); - UIATarget.localTarget().tap({x:width - 40, y:43}); + target.delay(2); - UIATarget.localTarget().frontMostApp().mainWindow().searchBars()[0].searchBars()[0].tap(); - writeInElement(UIATarget.localTarget().frontMostApp().mainWindow().searchBars()[0].searchBars()[0], "Yosemite") - UIATarget.localTarget().delay(2); + var searchBar = target.frontMostApp().mainWindow().searchBars()[0]; + searchBar.tap() + target.frontMostApp().keyboard().typeString("banana"); - UIATarget.localTarget().tap({x:width - 40, y:43}); - UIATarget.localTarget().frontMostApp().navigationBar().leftButton().tap(); + target.delay(1); + + target.tap({x:width - 40, y:43}); + + target.delay(1); + + searchBar.tap(); + target.delay(1); + + target.frontMostApp().keyboard().typeString("Yosemite"); + target.delay(1); + + target.tap({x:width - 40, y:43}); + + target.frontMostApp().navigationBar().leftButton().tap(); pass() }); - - - - - - - - - - - - diff --git a/scripts/automation-tests/03_masterDetail.js b/scripts/automation-tests/03_masterDetail.js index b2b8f0a6..07c0ed89 100644 --- a/scripts/automation-tests/03_masterDetail.js +++ b/scripts/automation-tests/03_masterDetail.js @@ -12,9 +12,11 @@ test("----- masterDetail -----", function (check, pass) { UIATarget.localTarget().frontMostApp().mainWindow().dragInsideWithOptions({startOffset:{x:0.93, y:yOffset(300)}, endOffset:{x:0.95, y:yOffset(200)}, duration:1.5}); UIATarget.localTarget().frontMostApp().mainWindow().dragInsideWithOptions({startOffset:{x:0.93, y:yOffset(300)}, endOffset:{x:0.95, y:yOffset(100)}, duration:1.5}); - UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[1].buttons()[0].tap(); + var firstCell = UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[1] - UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[1].buttons()[2].tap(); + firstCell.buttons()[0].tap(); + + firstCell.buttons()["Delete"].tap(); UIATarget.localTarget().delay( 2 ); @@ -25,15 +27,3 @@ test("----- masterDetail -----", function (check, pass) { pass() }); - - - - - - - - - - - - diff --git a/scripts/automation-tests/04_controlsTests.js b/scripts/automation-tests/04_controlsTests.js index 894c1e07..b6e4830d 100644 --- a/scripts/automation-tests/04_controlsTests.js +++ b/scripts/automation-tests/04_controlsTests.js @@ -1,7 +1,30 @@ -// UIATarget.localTarget().delay( 15 ); +test("----- UIAlertView tap -----", function (check, pass) { + UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[4].tap(); + + UIATarget.onAlert = function(alert){ + UIATarget.localTarget().onAlert = null + UIATarget.localTarget().frontMostApp().alert().buttons()["Three"].tap(); + UIATarget.localTarget().delay( 1 ); + + check(function () { + var textValue = UIATarget.localTarget().frontMostApp().mainWindow().staticTexts()["debugLabel"].value(); + return textValue === "UIAlertView didDismissWithButtonIndex 3"; + }); + + UIATarget.onAlert = function () { + return false; + }; + + UIATarget.localTarget().frontMostApp().navigationBar().leftButton().tap(); + return false; + } + + UIATarget.localTarget().frontMostApp().mainWindow().buttons()["Open AlertView"].tap(); + UIATarget.localTarget().delay( 4 ); +}); test("----- UIBarButtonItem tap -----", function (check, pass) { @@ -89,9 +112,9 @@ test("----- UITextField text -----", function (check, pass) { UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[4].tap(); - UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0].textFields()[0].tap(); + UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0].tap(); // UIATarget.localTarget().frontMostApp().keyboard().typeString("t");// fails if software keyboard is disabled - UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0].textFields()[0].setValue("t"); + UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0].setValue("t"); check(function () { var textValue = UIATarget.localTarget().frontMostApp().mainWindow().staticTexts()["debugLabel"].value(); @@ -157,30 +180,3 @@ test("----- UIActionSheet tap -----", function (check, pass) { UIATarget.localTarget().frontMostApp().navigationBar().leftButton().tap(); }); - - -test("----- UIAlertView tap -----", function (check, pass) { - - UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[4].tap(); - - UIATarget.localTarget().onAlert = function(alert){ - UIATarget.localTarget().onAlert = null - UIATarget.localTarget().frontMostApp().alert().buttons()["Three"].tap(); - UIATarget.localTarget().delay( 2 ); - - check(function () { - var textValue = UIATarget.localTarget().frontMostApp().mainWindow().staticTexts()["debugLabel"].value(); - return textValue === "UIAlertView didDismissWithButtonIndex 3"; - }); - - UIATarget.localTarget().onAlert = function () { - return false; - }; - - UIATarget.localTarget().frontMostApp().navigationBar().leftButton().tap(); - return false; - } - - UIATarget.localTarget().frontMostApp().mainWindow().buttons()["Open AlertView"].tap(); - UIATarget.localTarget().delay( 4 ); -}); diff --git a/scripts/automation-tests/05_reactivePartialUpdates.js b/scripts/automation-tests/05_reactivePartialUpdates.js index 1186165c..df4ea04b 100644 --- a/scripts/automation-tests/05_reactivePartialUpdates.js +++ b/scripts/automation-tests/05_reactivePartialUpdates.js @@ -2,7 +2,7 @@ test("----- reactivePartialUpdates -----", function (check, pass) { - UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[5].tap(); + UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[6].tap(); UIATarget.localTarget().frontMostApp().navigationBar().rightButton().tap(); UIATarget.localTarget().frontMostApp().navigationBar().rightButton().tap(); UIATarget.localTarget().frontMostApp().navigationBar().rightButton().tap(); @@ -14,15 +14,3 @@ test("----- reactivePartialUpdates -----", function (check, pass) { pass() }); - - - - - - - - - - - - diff --git a/scripts/automation-tests/common.js b/scripts/automation-tests/common.js index bb334f76..0991fa36 100644 --- a/scripts/automation-tests/common.js +++ b/scripts/automation-tests/common.js @@ -23,12 +23,12 @@ function test(testName, callback) { callback(check, pass) } -function log(string) { - UIALogger.logMessage(string) +function log(element) { + UIALogger.logMessage(element.toString()) } -function debug(string) { - UIALogger.logDebug(string) +function debug(element) { + UIALogger.logDebug(element.toString()) } function logElement(element) { @@ -48,10 +48,7 @@ function sleep(time) { } function writeInElement(element, text) { - var char for (var i = 1; i < text.length + 1; i++) { element.setValue(text.substring(0, i)); } } - - diff --git a/scripts/common.sh b/scripts/common.sh index 07e63247..a8b687f6 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -22,13 +22,11 @@ BOLDWHITE="\033[1m\033[37m" # make sure all tests are passing -DEFAULT_IOS7_SIMULATOR=RxSwiftTest-iPhone4s-iOS_7.1 -DEFAULT_IOS8_SIMULATOR=RxSwiftTest-iPhone6-iOS_8.4 -DEFAULT_IOS9_SIMULATOR=RxSwiftTest-iPhone6-iOS_9.0 -DEFAULT_WATCHOS2_SIMULATOR=RxSwiftTest-AppleWatch-watchOS_2.0 -DEFAULT_TVOS_SIMULATOR=RxSwiftTest-AppleTV-iOS_9.0 - -DEFAULT_IOS_SIMULATOR_RUNTIME="" +DEFAULT_IOS7_SIMULATOR=RxSwiftTest/iPhone-4s/iOS/7.1 +DEFAULT_IOS8_SIMULATOR=RxSwiftTest/iPhone-6/iOS/8.4 +DEFAULT_IOS9_SIMULATOR=RxSwiftTest/iPhone-6/iOS/9.0 +DEFAULT_WATCHOS2_SIMULATOR=RxSwiftTest/AppleWatch/watchOS/2.0 +DEFAULT_TVOS_SIMULATOR=RxSwiftTest/Apple-TV-1080p/tvOS/9.0 function runtime_available() { if [ `xcrun simctl list runtimes | grep "${1}" | wc -l` -eq 1 ]; then @@ -42,7 +40,7 @@ function runtime_available() { function contains() { string="$1" substring="$2" - if test "${string#*$substring}" != "$string" + if [[ $string == *"$substring"* ]] then return 0 # $substring is in $string else @@ -77,24 +75,34 @@ function simulator_available() { fi } -if [ "${IS_LOCAL}" == "1" ]; then -IOS7_SIMULATORS="RxSwiftTest-iPhone4s-iOS_7.1 RxSwiftTest-iPhone5-iOS_7.1 RxSwiftTest-iPhone5s-iOS_7.1" -IOS8_SIMULATORS="RxSwiftTest-iPhone4s-iOS_8.4 RxSwiftTest-iPhone5-iOS_8.4 RxSwiftTest-iPhone5s-iOS_8.4 RxSwiftTest-iPhone6-iOS_8.4 RxSwiftTest-iPhone6Plus-iOS_8.4" -else -IOS7_SIMULATORS="RxSwiftTest-iPhone4s-iOS_7.1" -IOS8_SIMULATORS="RxSwiftTest-iPhone4s-iOS_8.4" -fi +function is_real_device() { + contains "$1" "’s " +} +function ensure_simulator_available() { + SIMULATOR=$1 + + if simulator_available "${SIMULATOR}"; then + echo "${SIMULATOR} exists" + return + fi + + DEVICE=`echo "${SIMULATOR}" | cut -d "/" -f 2` + OS=`echo "${SIMULATOR}" | cut -d "/" -f 3` + VERSION_SUFFIX=`echo "${SIMULATOR}" | cut -d "/" -f 4 | sed -e "s/\./-/"` + + RUNTIME="com.apple.CoreSimulator.SimRuntime.${OS}-${VERSION_SUFFIX}" + + echo "Creating new simulator" + xcrun simctl create "${SIMULATOR}" "com.apple.CoreSimulator.SimDeviceType.${DEVICE}" "com.apple.CoreSimulator.SimRuntime.${OS}-${VERSION_SUFFIX}" +} if runtime_available "com.apple.CoreSimulator.SimRuntime.iOS-9-1"; then - DEFAULT_IOS9_SIMULATOR="RxSwiftTest-iPhone6-iOS_9.1" - DEFAULT_IOS_SIMULATOR_RUNTIME='com.apple.CoreSimulator.SimRuntime.iOS-9-1' + DEFAULT_IOS9_SIMULATOR=RxSwiftTest/iPhone-6/iOS/9.1 else - DEFAULT_IOS9_SIMULATOR="RxSwiftTest-iPhone6-iOS_9.0" - DEFAULT_IOS_SIMULATOR_RUNTIME='com.apple.CoreSimulator.SimRuntime.iOS-9-0' + DEFAULT_IOS9_SIMULATOR=RxSwiftTest/iPhone-6/iOS/9.0 fi - BUILD_DIRECTORY=build function rx() { @@ -108,14 +116,17 @@ function rx() { echo DESTINATION="" - if [ "$SIMULATOR" != "" ]; then - OS=`echo $SIMULATOR | cut -d'_' -f 2` - if contains $SIMULATOR "watchOS"; then - DESTINATION='platform=watchOS Simulator,OS='$OS',name='$SIMULATOR'' - elif contains $SIMULATOR "AppleTV"; then - DESTINATION='platform=tvOS Simulator,OS='$OS',name='$SIMULATOR'' + if [ "${SIMULATOR}" != "" ]; then + #if it's a real device + if is_real_device "${SIMULATOR}"; then + DESTINATION='name='${SIMULATOR} + #else it's just a simulator else - DESTINATION='platform=iOS Simulator,OS='$OS',name='$SIMULATOR'' + ensure_simulator_available "${SIMULATOR}" + OS=`echo $SIMULATOR | cut -d '/' -f 3` + SIMULATOR_GUID=`xcrun simctl list devices | grep ${SIMULATOR} | cut -d "(" -f 2 | cut -d ")" -f 1` + DESTINATION='platform='$OS' Simulator,OS='$OS',id='$SIMULATOR_GUID'' + echo "Running on ${DESTINATION}" fi else DESTINATION='platform=OS X,arch=x86_64' @@ -134,48 +145,3 @@ function rx() { exit $STATUS fi } - -# simulators - -# xcrun simctl list devicetypes -# xcrun simctl list runtimes - -function createDevices() { - xcrun simctl create RxSwiftTest-iPhone4s-iOS_7.1 'iPhone 4s' 'com.apple.CoreSimulator.SimRuntime.iOS-7-1' - xcrun simctl create RxSwiftTest-iPhone5-iOS_7.1 'iPhone 5' 'com.apple.CoreSimulator.SimRuntime.iOS-7-1' - xcrun simctl create RxSwiftTest-iPhone5s-iOS_7.1 'iPhone 5s' 'com.apple.CoreSimulator.SimRuntime.iOS-7-1' - - xcrun simctl create RxSwiftTest-iPhone4s-iOS_8.4 'iPhone 4s' 'com.apple.CoreSimulator.SimRuntime.iOS-8-4' - xcrun simctl create RxSwiftTest-iPhone5-iOS_8.4 'iPhone 5' 'com.apple.CoreSimulator.SimRuntime.iOS-8-4' - xcrun simctl create RxSwiftTest-iPhone5s-iOS_8.4 'iPhone 5s' 'com.apple.CoreSimulator.SimRuntime.iOS-8-4' - - xcrun simctl create RxSwiftTest-iPhone6-iOS_8.4 'iPhone 6' 'com.apple.CoreSimulator.SimRuntime.iOS-8-4' - xcrun simctl create RxSwiftTest-iPhone6Plus-iOS_8.4 'iPhone 6 Plus' 'com.apple.CoreSimulator.SimRuntime.iOS-8-4' - - xcrun simctl create RxSwiftTest-iPhone4s-iOS_9.0 'iPhone 4s' 'com.apple.CoreSimulator.SimRuntime.iOS-9-0' - xcrun simctl create RxSwiftTest-iPhone5-iOS_9.0 'iPhone 5' 'com.apple.CoreSimulator.SimRuntime.iOS-9-0' - xcrun simctl create RxSwiftTest-iPhone5s-iOS_9.0 'iPhone 5s' 'com.apple.CoreSimulator.SimRuntime.iOS-9-0' - - xcrun simctl create RxSwiftTest-iPhone6-iOS_9.0 'iPhone 6' 'com.apple.CoreSimulator.SimRuntime.iOS-9-0' - xcrun simctl create RxSwiftTest-iPhone6Plus-iOS_9.0 'iPhone 6 Plus' 'com.apple.CoreSimulator.SimRuntime.iOS-9-0' -} - -function deleteDevices() { - xcrun simctl delete RxSwiftTest-iPhone4s-iOS_7.1 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone5-iOS_7.1 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone5s-iOS_7.1 || echo "failed" - - xcrun simctl delete RxSwiftTest-iPhone4s-iOS_8.4 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone5-iOS_8.4 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone5s-iOS_8.4 || echo "failed" - - xcrun simctl delete RxSwiftTest-iPhone6-iOS_8.4 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone6Plus-iOS_8.4 || echo "failed" - - xcrun simctl delete RxSwiftTest-iPhone4s-iOS_9.0 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone5-iOS_9.0 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone5s-iOS_9.0 || echo "failed" - - xcrun simctl delete RxSwiftTest-iPhone6-iOS_9.0 || echo "failed" - xcrun simctl delete RxSwiftTest-iPhone6Plus-iOS_9.0 || echo "failed" -} diff --git a/scripts/pre-release-tests.sh b/scripts/pre-release-tests.sh index 27641b42..81771800 100755 --- a/scripts/pre-release-tests.sh +++ b/scripts/pre-release-tests.sh @@ -1,20 +1,17 @@ +. scripts/common.sh -IS_LOCAL=0 -IS_QUICK=1 -if [ "$1" == "l" ]; then - echo "Local test" - IS_LOCAL=1 -fi - -if [ "$1" == "f" ]; then - echo "Full" - IS_QUICK=0 -else - echo "Quick" -fi - -ISLOCAL="${IS_LOCAL}" . scripts/common.sh TV_OS=0 +RELEASE_TEST=0 + +if [ `xcodebuild -showsdks | grep tvOS | wc -l` -ge 4 ]; then + printf "${GREEN}tvOS found${RESET}\n" + TV_OS=1 +fi + +if [ "$1" == "r" ]; then + printf "${GREEN}Pre release tests on, hang on tight ...${RESET}" + RELEASE_TEST=1 +fi # ios 7 sim #if [ `xcrun simctl list | grep "${DEFAULT_IOS7_SIMULATOR}" | wc -l` == 0 ]; then @@ -30,43 +27,11 @@ TV_OS=0 # echo "${DEFAULT_IOS8_SIMULATOR} exists" #fi -if [ "${IS_LOCAL}" -eq 1 ]; then +if [ "${RELEASE_TEST}" -eq 1 ]; then . scripts/automation-tests.sh fi -if [ `xcodebuild -showsdks | grep tvOS | wc -l` -ge 4 ]; then - printf "${GREEN}tvOS found${RESET}\n" - TV_OS=1 -fi - -#ios 9 sim -if simulator_available "${DEFAULT_IOS9_SIMULATOR}"; then - echo "${DEFAULT_IOS9_SIMULATOR} exists" -else - xcrun simctl create "${DEFAULT_IOS9_SIMULATOR}" 'iPhone 6' "${DEFAULT_IOS_SIMULATOR_RUNTIME}" -fi - -#watch os 2 sim -if simulator_available "${DEFAULT_WATCHOS2_SIMULATOR}"; then - echo "${DEFAULT_WATCHOS2_SIMULATOR} exists" -else - xcrun simctl create "${DEFAULT_WATCHOS2_SIMULATOR}" 'Apple Watch - 38mm' 'com.apple.CoreSimulator.SimRuntime.watchOS-2-0' -fi - -#watch os 2 sim -if [ "${TV_OS}" -eq 1 ]; then - if simulator_available "${DEFAULT_TVOS_SIMULATOR}"; then - echo "${DEFAULT_TVOS_SIMULATOR} exists" - else - xcrun simctl create $DEFAULT_TVOS_SIMULATOR 'Apple TV 1080p' 'com.apple.CoreSimulator.SimRuntime.tvOS-9-0' - fi -fi - -if [ "${IS_QUICK}" -eq 1 ]; then - CONFIGURATIONS=(Release) -else - CONFIGURATIONS=(Debug Release-Tests Release) -fi +CONFIGURATIONS=(Release) # make sure watchos builds # temporary solution @@ -148,7 +113,7 @@ do done done -if [ "${IS_LOCAL}" -eq 1 ]; then +if [ "${RELEASE_TEST}" -eq 1 ]; then mdast -u mdast-slug -u mdast-validate-links ./*.md mdast -u mdast-slug -u mdast-validate-links ./**/*.md fi diff --git a/scripts/validate-podspec.sh b/scripts/validate-podspec.sh new file mode 100755 index 00000000..ec516a67 --- /dev/null +++ b/scripts/validate-podspec.sh @@ -0,0 +1,34 @@ +# This is kind of naughty, I know, +# but we need to know what will the state be once RxSwift is deployed. + +set -e + +VERSION=`cat RxSwift.podspec | grep -E "s.version\s+=" | cut -d '"' -f 2` + +pushd ~/.cocoapods/repos/master +pushd Specs + +mkdir -p RxSwift/${VERSION} +mkdir -p RxCocoa/${VERSION} +mkdir -p RxBlocking/${VERSION} + +popd +popd + +cat RxSwift.podspec | +sed -E "s/s.source[^\}]+\}/s.source = { :git => '\/Users\/kzaher\/Projects\/Rx', :branch => \'develop\' }/" > ~/.cocoapods/repos/master/Specs/RxSwift/${VERSION}/RxSwift.podspec + +cat RxCocoa.podspec | +sed -E "s/s.source[^\}]+\}/s.source = { :git => '\/Users\/kzaher\/Projects\/Rx', :branch => \'develop\' }/" > ~/.cocoapods/repos/master/Specs/RxCocoa/${VERSION}/RxCocoa.podspec + +cat RxBlocking.podspec | +sed -E "s/s.source[^\}]+\}/s.source = { :git => '\/Users\/kzaher\/Projects\/Rx', :branch => \'develop\' }/" > ~/.cocoapods/repos/master/Specs/RxBlocking/${VERSION}/RxBlocking.podspec + +pod lib lint RxSwift.podspec +pod lib lint RxCocoa.podspec +pod lib lint RxBlocking.podspec + +pushd ~/.cocoapods/repos/master +git clean -d -f +git reset master --hard +popd