diff --git a/README.md b/README.md index c45f7bd..d41cc11 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,13 @@ SwiftTask ![SwiftTask](Screenshots/diagram.png) +### Ver 2.0.0 Changelog (2014/11/18) + +- `task.progress()`'s `progressClosure` type changed from `Progress -> Void` to `(oldProgress: Progress?, newProgress: Progress) -> Void` +- `task.then(fulfilledClosure)` is renamed to `task.success()` +- `task.catch(catchClosure)` is renamed to `task.failure()` +- `task.then()` is no longer used for fulfilled-only handling (this will improve Swift type-inference) + ## Example @@ -12,7 +19,7 @@ SwiftTask ```swift // define task -let task = Task { (progress, fulfill, reject, configure) in +let task = Task { progress, fulfill, reject, configure in player.doSomethingWithProgress({ (progressValue: Float) in progress(progressValue) // optional @@ -38,10 +45,10 @@ let task = Task { (progress, fulfill, reject, configure) } -// set then & catch -task.then { (value: String) -> Void in +// set onSuccess & onFailure +task.onSuccess { (value: String) -> Void in // do something with fulfilled value -}.catch { (error: NSError?, isCancelled: Bool) -> Void in +}.onFailure { (error: NSError?, isCancelled: Bool) -> Void in // do something with rejected error } @@ -65,16 +72,17 @@ One of the best example would be [Alamofire](https://github.com/Alamofire/Alamof ```swift typealias Progress = (bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) +typealias AlamoFireTask = Task // define task -let task = Task { (progress, fulfill, reject, configure) in +let task = AlamoFireTask { progress, fulfill, reject, configure in Alamofire.download(.GET, "http://httpbin.org/stream/100", destination: somewhere) - .progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in + .progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in progress((bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) as Progress) - }.response { (request, response, data, error) in + }.response { request, response, data, error in if let error = error { reject(error) @@ -88,15 +96,15 @@ let task = Task { (progress, fulfill, reject, configu return } -// set progress & then -task.progress { progress in +// set onProgress & onComplete +task.onProgress { (oldProgress: Progress?, newProgress: Progress) in - println("\(progress.bytesWritten)") - println("\(progress.totalBytesWritten)") - println("\(progress.totalBytesExpectedToWrite)") + println("\(newProgress.bytesWritten)") + println("\(newProgress.totalBytesWritten)") + println("\(newProgress.totalBytesExpectedToWrite)") -}.then { (value: String) -> Void in - // do something with fulfilled value +}.onComplete { (value: String?, errorInfo: AlamoFireTask.ErrorInfo?) -> Void in + // do something with fulfilled value or rejected errorInfo } ``` @@ -107,10 +115,10 @@ For more examples, please see XCTest cases. ### Task.init(closure:) -Define your `task` inside `closure`. +Define your `task` inside `initClosure`. ```swift -let task = Task { (progress, fulfill, reject, configure) in +let task = Task { progress, fulfill, reject, configure in player.doSomethingWithCompletion { (value: NSString?, error: NSError?) in if error == nil { @@ -123,9 +131,9 @@ let task = Task { (progress, fulfill, reject, configu } ``` -In order to pipeline future `task.value` or `task.errorInfo` (tuple of `(error: Error?, isCancelled: Bool)`) via `then` and `catch` methods, you have to call `fulfill(value)` and `reject(error)` inside closure. +In order to pipeline future `task.value` or `task.errorInfo` (tuple of `(error: Error?, isCancelled: Bool)`) via `onComplete()`/`onSuccess()`/`onFailure()`, you have to call `fulfill(value)` and/or `reject(error)` inside `initClosure`. -Optionally, you can call `progress(progressValue)` multiple times before calling `fulfill`/`reject` to transfer `progressValue` outside of the closure, notifying it to `task` itself. +Optionally, you can call `progress(progressValue)` multiple times before calling `fulfill`/`reject` to transfer `progressValue` outside of the `initClosure`, notifying it to `task` itself. To add `pause`/`resume`/`cancel` functionality to your `task`, use `configure` to wrap up the original one. @@ -142,117 +150,94 @@ configure.cancel = { [weak player] in } ``` -### task.progress(_ progressClosure:) -> task +### task.onProgress(_ progressClosure:) -> task ```swift -task.progress { (progressValue: Progress) in - println(progressValue) +task.onProgress { (oldValue: Progress?, newValue: Progress) in + println(newValue) return -}.then { ... } +}.onSuccess { ... } ``` -`task.progress(progressClosure)` will add `progressClosure` to observe `progressValue` which is notified from inside previous init-closure. This method will return same task, so it is useful to chain with forthcoming `then` and `catch`. - - -### task.then(_ closure:) -> newTask +`task.onProgress(progressClosure)` will add `progressClosure` to observe `progressValue` which is notified from inside previous `initClosure`. This method will return **same task**, so it is useful to chain with forthcoming `onComplete`/`onSuccess`/`onFailure`. -`task.then(closure)` will return a new task which behaves differently depending on what kind of `closure` is passed in. - -1. `closure` used for **fulfilled only** -2. `closure` used for both **fulfilled & rejected** - -#### 1. closure used for fulfilled only = `fulfilledClosure` - -`fulfilledClosure` will be invoked only when `task` is only *fulfilled*. - -This case is similar to JavaScript's `promise.then(onFulfilled)`. +### task.onComplete(_ completeClosure:) -> newTask -- `fulfilledClosure: Value -> Value2` (flow: *task => newTask*) - - ```swift - // task will be fulfilled with value "Hello" - - task.then { (value: String) -> String in - return "\(value) World" // string value returns new string - }.then { (value: String) -> Void in - println("\(value)") // Hello World - return" - } - ``` - -- `fulfilledClosure: Value -> Task` (flow: *task => task2 => newTask*) - - ```swift - // task will be fulfilled with value "Hello" - // task2 will be fulfilled with value "\(value) Swift" - - task.then { (value: String) -> Task in - let task2 = ... // fulfilling "\(value) Swift" - return task2 - }.then { (value: String) -> Void in - println("\(value)") // Hello Swift - return" - } - ``` - -#### 2. closure for both fulfilled & rejected = `thenClosure` - -In this case, `thenClosure` will be invoked when `task` is either *fulfilled* or *rejected*. This means, `thenClosure` is mostly called in future compared to `fulfilledClosure`, which is invoked only when *fulfilled*. +`task.onComplete(completeClosure)` will return a new task where `completeClosure` will be invoked when `task` is either **fulfilled** or **rejected**. This case is similar to JavaScript's `promise.then(onFulfilled, onRejected)`. -- `thenClosure: (Value?, ErrorInfo?) -> Value2` (flow: *task => newTask*) +`completeClosure` can be two types of closure form: + +1. `completeClosure: (Value?, ErrorInfo?) -> Value2` (flow: *task => newTask*) ```swift - // task will be fulfilled with value "Hello" + // let task will be fulfilled with value "Hello" - task.then { (value: String?, errorInfo: ErrorInfo?) -> String in + task.onComplete { (value: String?, errorInfo: ErrorInfo?) -> String in // nil-check to find out whether task is fulfilled or rejected if errorInfo == nil { - return "\(value) World" // string value returns new string + return "\(value!) World" } else { - return "\(value) Error" + return "\(value!) Error" } - }.then { (value: String) -> Void in + }.onSuccess { (value: String) -> Void in println("\(value)") // Hello World return" } ``` -- `thenClosure: (Value?, ErrorInfo?) -> Task` (flow: *task => task2 => newTask*) +2. `completeClosure: (Value?, ErrorInfo?) -> Task` (flow: *task => task2 => newTask*) ```swift - // task will be fulfilled with value "Hello" - // task2 will be fulfilled with value "\(value) Swift" + // let task will be fulfilled with value "Hello" - task.then { (value: String) -> Task in + task.onComplete { (value: String?, errorInfo: ErrorInfo?) -> Task in if errorInfo == nil { - let task2 = ... // fulfilling "\(value) Swift" + // let task2 will be fulfilled with value "\(value!) Swift" + let task2 = ... return task2 } else { return someOtherTask } - }.then { (value: String) -> Void in + }.onSuccess { (value: String) -> Void in println("\(value)") // Hello Swift return" } ``` -### task.catch(_ catchClosure:) -> newTask +### task.onSuccess(_ successClosure:) -> newTask + +Similar to `onComplete()` method, `task.onSuccess(successClosure)` will return a new task, but this time, `successClosure` will be invoked when task is **only fulfilled**. + +This case is similar to JavaScript's `promise.then(onFulfilled)`. + +```swift +// let task will be fulfilled with value "Hello" + +task.onSuccess { (value: String) -> String in + return "\(value) World" +}.onSuccess { (value: String) -> Void in + println("\(value)") // Hello World + return" +} +``` + +### task.onFailure(_ failureClosure:) -> newTask -Similar to `task.then(fulfilledClosure)` for fulfilled only, `task.catch(catchClosure)` will invoke `catchClosure` only when `task` is either *rejected* or *cancelled*. +Just the opposite of `onSuccess()`, `task.onFailure(failureClosure)` will return a new task where `failureClosure` will be invoked when task is **only rejected/cancelled**. This case is similar to JavaScript's `promise.then(undefined, onRejected)` or `promise.catch(onRejected)`. ```swift -// task will be rejected with error "Oh My God" +// let task will be rejected with error "Oh My God" -task.then { (value: String) -> Void in +task.onSuccess { (value: String) -> Void in println("\(value)") // never reaches here return -}.catch { (error: NSError?, isCancelled: Bool) -> Void in +}.onFailure { (error: NSError?, isCancelled: Bool) -> Void in println("\(error!)") // Oh My God return } @@ -262,24 +247,24 @@ task.then { (value: String) -> Void in `Task.all(tasks)` is a new task that performs all `tasks` simultaneously and will be: -- fulfilled when **all tasks will be fulfilled** -- rejected when **any of the task will be rejected** +- fulfilled when **all tasks are fulfilled** +- rejected when **any of the task is rejected** ### Task.any(_ tasks:) -> newTask `Task.any(tasks)` is an opposite of `Task.all(tasks)` which will be: -- fulfilled when **any of the task will be fulfilled** -- rejected when **all tasks will be rejected** +- fulfilled when **any of the task is fulfilled** +- rejected when **all tasks are rejected** ### Task.some(_ tasks:) -> newTask -`Task.some(tasks)` is a new task that performs all `tasks` without internal rejection, and is fulfilled with given `tasks`'s fulfilled values. Note that this new task will also become *fulfilled* with empty value-array, even though all `tasks` are rejected. +`Task.some(tasks)` is a new task that performs all `tasks` without internal rejection, and is fulfilled with given `tasks`'s fulfilled values. Note that this new task **will be fulfilled with empty value-array, even though all `tasks` are rejected.** ## Related Articles -- [SwiftTask(Promise拡張)を使う - Qiita](http://qiita.com/inamiy/items/0756339aee35849384c3) (Japanese) +- [SwiftTask(Promise拡張)を使う - Qiita](http://qiita.com/inamiy/items/0756339aee35849384c3) (Japanese, ver 1.0.0) ## Licence diff --git a/SwiftTask/SwiftTask.swift b/SwiftTask/SwiftTask.swift index 29fec91..b018ba3 100644 --- a/SwiftTask/SwiftTask.swift +++ b/SwiftTask/SwiftTask.swift @@ -118,11 +118,11 @@ public class Task /// /// Creates new task. - /// e.g. Task(weakified: false) { (progress, fulfill, reject, configure) in ... } + /// e.g. Task(weakified: false) { progress, fulfill, reject, configure in ... } /// /// :param: weakified Weakifies progress/fulfill/reject handlers to let player (inner asynchronous implementation inside initClosure) NOT CAPTURE this created new task. Normally, weakified = false should be set to gain "player -> task" retaining, so that task will be automatically deinited when player is deinited. If weakified = true, task must be manually retained somewhere else, or it will be immediately deinited. /// - /// :param: initClosure e.g. { (progress, fulfill, reject, configure) in ... }. fulfill(value) and reject(error) handlers must be called inside this closure, where calling progress(progressValue) handler is optional. Also as options, configure.pause/resume/cancel closures can be set to gain control from outside e.g. task.pause()/resume()/cancel(). When using configure, make sure to use weak modifier when appropriate to avoid "task -> player" retaining which often causes retain cycle. + /// :param: initClosure e.g. { progress, fulfill, reject, configure in ... }. fulfill(value) and reject(error) handlers must be called inside this closure, where calling progress(progressValue) handler is optional. Also as options, configure.pause/resume/cancel closures can be set to gain control from outside e.g. task.pause()/resume()/cancel(). When using configure, make sure to use weak modifier when appropriate to avoid "task -> player" retaining which often causes retain cycle. /// /// :returns: New task. /// @@ -144,7 +144,7 @@ public class Task /// creates fulfilled task public convenience init(value: Value) { - self.init(initClosure: { (progress, fulfill, reject, configure) in + self.init(initClosure: { progress, fulfill, reject, configure in fulfill(value) return }) @@ -153,7 +153,7 @@ public class Task /// creates rejected task public convenience init(error: Error) { - self.init(initClosure: { (progress, fulfill, reject, configure) in + self.init(initClosure: { progress, fulfill, reject, configure in reject(error) return }) @@ -162,7 +162,7 @@ public class Task /// creates promise-like task which only allows fulfill & reject (no progress & configure) public convenience init(promiseInitClosure: PromiseInitClosure) { - self.init(initClosure: { (progress, fulfill, reject, configure) in + self.init(initClosure: { progress, fulfill, reject, configure in promiseInitClosure(fulfill: fulfill, reject: { (error: Error) in reject(error) }) return }) @@ -199,7 +199,7 @@ public class Task } // TODO: how to nest these inside StateMachine's initClosure? (using `self` is not permitted) - // NOTE: use order > 100 (default) to let `progressTupleClosure(self.progress, newValue)` be invoked first before updating old `self.progress` + // NOTE: use order > 100 (default) to let `progressClosure(self.progress, newProgress)` be invoked first before updating old `self.progress` self.machine.addEventHandler(.Progress, order: 110) { [weak self] context in if let progress = context.userInfo as? Progress { if let self_ = self { @@ -278,33 +278,18 @@ public class Task self._cancel(error: nil) } - /// progress + newValue only - public func progress(progressClosure: Progress -> Void) -> Task + public func progress(progressClosure: (oldProgress: Progress?, newProgress: Progress) -> Void) -> Task { self.machine.addEventHandler(.Progress) { [weak self] context in if let progress = context.userInfo as? Progress { - progressClosure(progress) + progressClosure(oldProgress: self?.progress, newProgress: progress) } } return self } - /// progress + (oldValue, newValue) - public func progress(progressTupleClosure: (oldValue: Progress?, newValue: Progress) -> Void) -> Task - { - self.machine.addEventHandler(.Progress) { [weak self] context in - if let progress = context.userInfo as? Progress { - if let self_ = self { - progressTupleClosure(oldValue: self_.progress, newValue: progress) - } - } - } - - return self - } - - /// then (fulfilled & rejected) + returning value + /// then (fulfilled & rejected) + closure returning value public func then(thenClosure: (Value?, ErrorInfo?) -> Value2) -> Task { return self.then { (value: Value?, errorInfo: ErrorInfo?) -> Task in @@ -312,7 +297,7 @@ public class Task } } - /// then (fulfilled & rejected) + returning task + /// then (fulfilled & rejected) + closure returning task public func then(thenClosure: (Value?, ErrorInfo?) -> Task) -> Task { let newTask = Task { [weak self] (progress, fulfill, _reject: _RejectHandler, configure) in @@ -320,7 +305,7 @@ public class Task let bind = { (value: Value?, errorInfo: ErrorInfo?) -> Void in let innerTask = thenClosure(value, errorInfo) - // NOTE: don't call then/catch for innerTask, or recursive bindings may occur + // NOTE: don't call `then` for innerTask, or recursive bindings may occur // Bad example: https://github.com/inamiy/SwiftTask/blob/e6085465c147fb2211fb2255c48929fcc07acd6d/SwiftTask/SwiftTask.swift#L312-L316 switch innerTask.machine.state { case .Fulfilled: @@ -370,16 +355,16 @@ public class Task return newTask } - /// then (fulfilled only) + returning value - public func then(fulfilledClosure: Value -> Value2) -> Task + /// success (fulfilled) + closure returning value + public func success(fulfilledClosure: Value -> Value2) -> Task { - return self.then { (value: Value) -> Task in + return self.success { (value: Value) -> Task in return Task(value: fulfilledClosure(value)) } } - /// then (fulfilled only) + returning task - public func then(fulfilledClosure: Value -> Task) -> Task + /// success (fulfilled) + closure returning task + public func success(fulfilledClosure: Value -> Task) -> Task { let newTask = Task { [weak self] (progress, fulfill, _reject: _RejectHandler, configure) in @@ -425,21 +410,21 @@ public class Task return newTask } - /// catch + returning value - public func catch(catchClosure: ErrorInfo -> Value) -> Task + /// failure (rejected) + closure returning value + public func failure(failureClosure: ErrorInfo -> Value) -> Task { - return self.catch { (errorInfo: ErrorInfo) -> Task in - return Task(value: catchClosure(errorInfo)) + return self.failure { (errorInfo: ErrorInfo) -> Task in + return Task(value: failureClosure(errorInfo)) } } - /// catch + returning task - public func catch(catchClosure: ErrorInfo -> Task) -> Task + /// failure (rejected) + closure returning task + public func failure(failureClosure: ErrorInfo -> Task) -> Task { let newTask = Task { [weak self] (progress, fulfill, _reject: _RejectHandler, configure) in let bind = { (errorInfo: ErrorInfo) -> Void in - let innerTask = catchClosure(errorInfo) + let innerTask = failureClosure(errorInfo) innerTask.then { (value: Value?, errorInfo: ErrorInfo?) -> Void in if let value = value { @@ -512,7 +497,7 @@ extension Task let totalCount = tasks.count for task in tasks { - task.then { (value: Value) -> Void in + task.success { (value: Value) -> Void in synchronized(self) { completedCount++ @@ -531,7 +516,7 @@ extension Task } } - }.catch { (errorInfo: ErrorInfo) -> Void in + }.failure { (errorInfo: ErrorInfo) -> Void in synchronized(self) { _reject(errorInfo) @@ -559,7 +544,7 @@ extension Task let totalCount = tasks.count for task in tasks { - task.then { (value: Value) -> Void in + task.success { (value: Value) -> Void in synchronized(self) { completedCount++ @@ -571,7 +556,7 @@ extension Task } } - }.catch { (errorInfo: ErrorInfo) -> Void in + }.failure { (errorInfo: ErrorInfo) -> Void in synchronized(self) { rejectedCount++ @@ -594,7 +579,7 @@ extension Task } /// Returns new task which performs all given tasks and stores only fulfilled values. - /// This new task will NEVER be internally rejected (thus uncatchable from outside). + /// This new task will NEVER be internally rejected. public class func some(tasks: [Task]) -> Task { return Task { (progress, fulfill, _reject: _RejectHandler, configure) in diff --git a/SwiftTaskTests/AlamofireTests.swift b/SwiftTaskTests/AlamofireTests.swift index 16ee7d1..cb78338 100644 --- a/SwiftTaskTests/AlamofireTests.swift +++ b/SwiftTaskTests/AlamofireTests.swift @@ -17,7 +17,7 @@ class AlamofireTests: _TestCase { var expect = self.expectationWithDescription(__FUNCTION__) - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]) .response { (request, response, data, error) in @@ -52,7 +52,7 @@ class AlamofireTests: _TestCase { var expect = self.expectationWithDescription(__FUNCTION__) - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in let dummyURLString = "http://xxx-swift-task.org/get" @@ -78,7 +78,7 @@ class AlamofireTests: _TestCase XCTFail("Should never reach here.") - }.catch { (error: NSError?, isCancelled: Bool) -> Void in + }.failure { (error: NSError?, isCancelled: Bool) -> Void in // println(error) @@ -96,7 +96,7 @@ class AlamofireTests: _TestCase var expect = self.expectationWithDescription(__FUNCTION__) // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in download(.GET, "http://httpbin.org/stream/100", Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)) @@ -146,7 +146,7 @@ class AlamofireTests: _TestCase var nsProgress = NSProgress(totalUnitCount: 100) // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in nsProgress.becomeCurrentWithPendingUnitCount(50) @@ -199,7 +199,7 @@ class AlamofireTests: _TestCase { var expect = self.expectationWithDescription(__FUNCTION__) - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in let downloadRequst = download(.GET, "http://httpbin.org/stream/100", Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)) @@ -226,13 +226,13 @@ class AlamofireTests: _TestCase } } - } // end of 1st task definition (NOTE: don't chain with `then` or `catch` for 1st task cancellation) + } // end of 1st task definition (NOTE: don't chain with `then` or `failure` for 1st task cancellation) task.then { (value: String?) -> Void in XCTFail("Should never reach here because task is cancelled.") - }.catch { (error: NSError?, isCancelled: Bool) -> Void in + }.failure { (error: NSError?, isCancelled: Bool) -> Void in // println(error) diff --git a/SwiftTaskTests/BasicTests.swift b/SwiftTaskTests/BasicTests.swift index 0a774b0..4a90fe8 100644 --- a/SwiftTaskTests/BasicTests.swift +++ b/SwiftTaskTests/BasicTests.swift @@ -19,7 +19,7 @@ class BasicTests: _TestCase var progressCount = 0 // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in Async.main(after: 0.1) { progress(0.0) @@ -35,22 +35,22 @@ class BasicTests: _TestCase return } + + task.progress { oldProgress, newProgress in - task.progress { (progress: Float) in - - println("progress = \(progress)") + println("progress = \(newProgress)") - }.then { (value: String) -> String in // then(onFulfilled) + }.success { value -> String in // `task.success {...}` = JavaScript's `promise.then(onFulfilled)` XCTAssertEqual(value, "OK") return "Now OK" - - }.catch { (error: ErrorString?, isCancelled: Bool) -> String in // catch(onRejected) + + }.failure { error, isCancelled -> String in // `task.failure {...}` = JavaScript's `promise.catch(onRejected)` XCTAssertEqual(error!, "ERROR") return "Now RECOVERED" - }.then { (value: String?, errorInfo: Task.ErrorInfo?) -> Task in // then(onFulfilled+onRejected) + }.then { value, errorInfo -> Task in // `task.then {...}` = JavaScript's `promise.then(onFulfilled, onRejected)` println("value = \(value)") // either "Now OK" or "Now RECOVERED" @@ -59,7 +59,7 @@ class BasicTests: _TestCase return Task(error: "ABORT") - }.then { (value: String?, errorInfo: Task.ErrorInfo?) -> Void in // then(onFulfilled+onRejected) + }.then { value, errorInfo -> Void in println("errorInfo = \(errorInfo)") diff --git a/SwiftTaskTests/RetainCycleTests.swift b/SwiftTaskTests/RetainCycleTests.swift index 3ac3040..1a8fd50 100644 --- a/SwiftTaskTests/RetainCycleTests.swift +++ b/SwiftTaskTests/RetainCycleTests.swift @@ -61,7 +61,7 @@ class RetainCycleTests: _TestCase // 2. dispatch_queue x-> player // dispatch_queue (via player impl) x-> player (via completion capturing) // - self.task = Task { (progress, fulfill, reject, configure) in + self.task = Task { progress, fulfill, reject, configure in let player = Player() self.player = player @@ -78,9 +78,7 @@ class RetainCycleTests: _TestCase XCTAssertNotNil(self.task, "self.task (weak) should NOT be nil because of retain cycle: task <- dispatch_queue.") XCTAssertNotNil(self.player, "self.player (weak) should NOT nil because player is not retained by dispatch_queue.") - println("then") - - self.task!.then { (value: String) -> Void in + self.task!.success { value -> Void in XCTAssertEqual(value, "OK") expect.fulfill() @@ -110,7 +108,7 @@ class RetainCycleTests: _TestCase // 3. task -> player // task -> task.machine -> configure (via pause/resume addEventHandler) -> configure.cancel -> player // - self.task = Task { (progress, fulfill, reject, configure) in + self.task = Task { progress, fulfill, reject, configure in let player = Player() self.player = player @@ -126,9 +124,7 @@ class RetainCycleTests: _TestCase XCTAssertNotNil(self.task, "self.task (weak) should NOT be nil because of retain cycle: task <- dispatch_queue.") XCTAssertNotNil(self.player, "self.player (weak) should NOT be nil because of retain cycle: player <- configure <- task.") - println("then") - - self.task!.then { (value: String) -> Void in + self.task!.success { value -> Void in XCTAssertEqual(value, "OK") expect.fulfill() @@ -152,7 +148,7 @@ class RetainCycleTests: _TestCase // 1. dispatch_queue x-> player -> task // dispatch_queue (via player impl) x-> player -> player.completionHandler -> fulfill -> task // - self.task = Task { (progress, fulfill, reject, configure) in + self.task = Task { progress, fulfill, reject, configure in let player = Player() self.player = player @@ -170,9 +166,7 @@ class RetainCycleTests: _TestCase XCTAssertNotNil(self.task, "self.task (weak) should not be nil because of retain cycle: task <- player <- dispatch_queue.") XCTAssertNotNil(self.player, "self.player (weak) should not be nil because of retain cycle: player <- configure <- task.") - println("then") - - self.task!.then { (value: String) -> Void in + self.task!.success { value -> Void in XCTAssertEqual(value, "OK") expect.fulfill() @@ -199,7 +193,7 @@ class RetainCycleTests: _TestCase // 2. task x-> player // task -> task.machine -> configure (via pause/resume addEventHandler) -> configure.pause/resume/cancel x-> player // - self.task = Task { (progress, fulfill, reject, configure) in + self.task = Task { progress, fulfill, reject, configure in let player = Player() self.player = player @@ -216,9 +210,7 @@ class RetainCycleTests: _TestCase XCTAssertNotNil(self.task, "self.task (weak) should not be nil because of retain cycle: task <- player <- dispatch_queue.") XCTAssertNotNil(self.player, "self.player (weak) should not be nil because of retain cycle: player <- configure <- task.") - println("then") - - self.task!.then { (value: String) -> Void in + self.task!.success { value -> Void in XCTAssertEqual(value, "OK") expect.fulfill() diff --git a/SwiftTaskTests/SwiftTaskTests.swift b/SwiftTaskTests/SwiftTaskTests.swift index bc8e807..7336da2 100644 --- a/SwiftTaskTests/SwiftTaskTests.swift +++ b/SwiftTaskTests/SwiftTaskTests.swift @@ -29,7 +29,7 @@ class SwiftTaskTests: _TestCase // NOTE: this is non-async test if self.isAsync { return } - Task(value: "OK").then { (value: String) -> Void in + Task(value: "OK").success { value -> Void in XCTAssertEqual(value, "OK") } } @@ -39,7 +39,7 @@ class SwiftTaskTests: _TestCase // NOTE: this is non-async test if self.isAsync { return } - Task(error: "ERROR").catch { (error: String?, isCancelled: Bool) -> String in + Task(error: "ERROR").failure { error, isCancelled -> String in XCTAssertEqual(error!, "ERROR") return "RECOVERY" @@ -53,12 +53,12 @@ class SwiftTaskTests: _TestCase // NOTE: this is non-async test if self.isAsync { return } - Task { (fulfill, reject) in + Task { fulfill, reject in fulfill("OK") return - }.then { (value: String) -> Void in + }.success { value -> Void in XCTAssertEqual(value, "OK") } } @@ -67,42 +67,42 @@ class SwiftTaskTests: _TestCase // MARK: - Fulfill //-------------------------------------------------- - func testFulfill_then() + func testFulfill_success() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { fulfill("OK") } - }.then { (value: String) -> Void in - + }.success { value -> Void in + XCTAssertEqual(value, "OK") expect.fulfill() - + } self.wait() } - func testFulfill_then_catch() + func testFulfill_success_failure() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { fulfill("OK") } - }.then { (value: String) -> Void in + }.success { value -> Void in XCTAssertEqual(value, "OK") expect.fulfill() - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTFail("Should never reach here.") @@ -111,25 +111,25 @@ class SwiftTaskTests: _TestCase self.wait() } - func testFulfill_catch_then() + func testFulfill_failure_success() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { fulfill("OK") } - }.catch { (error: ErrorString?, isCancelled: Bool) -> String in + }.failure { error, isCancelled -> String in XCTFail("Should never reach here.") return "RECOVERY" - }.then { (value: String) -> Void in + }.success { value -> Void in - XCTAssertEqual(value, "OK", "value should be derived from 1st task, passing through 2nd catching task.") + XCTAssertEqual(value, "OK", "value should be derived from 1st task, passing through 2nd failure task.") expect.fulfill() } @@ -137,21 +137,21 @@ class SwiftTaskTests: _TestCase self.wait() } - func testFulfill_thenTaskFulfill() + func testFulfill_successTaskFulfill() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { fulfill("OK") } - }.then { (value: String) -> Task in + }.success { value -> Task in XCTAssertEqual(value, "OK") - return Task { (progress, fulfill, reject, configure) in + return Task { progress, fulfill, reject, configure in self.perform { fulfill("OK2") @@ -159,7 +159,7 @@ class SwiftTaskTests: _TestCase } - }.then { (value: String) -> Void in + }.success { value -> Void in XCTAssertEqual(value, "OK2") @@ -169,21 +169,21 @@ class SwiftTaskTests: _TestCase self.wait() } - func testFulfill_thenTaskReject() + func testFulfill_successTaskReject() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { fulfill("OK") } - }.then { (value: String) -> Task in + }.success { value -> Task in XCTAssertEqual(value, "OK") - return Task { (progress, fulfill, reject, configure) in + return Task { progress, fulfill, reject, configure in self.perform { reject("ERROR") @@ -191,11 +191,11 @@ class SwiftTaskTests: _TestCase } - }.then { (value: String) -> Void in + }.success { value -> Void in XCTFail("Should never reach here.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "ERROR") XCTAssertFalse(isCancelled) @@ -207,26 +207,26 @@ class SwiftTaskTests: _TestCase self.wait() } - func testFulfill_then2() + func testFulfill_then() { typealias Task = SwiftTask.Task var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { fulfill("OK") } - }.then { (value: String?, errorInfo: Task.ErrorInfo?) -> String in + }.then { value, errorInfo -> String in // thenClosure can handle both fulfilled & rejected XCTAssertEqual(value!, "OK") XCTAssertTrue(errorInfo == nil) return "OK2" - - }.then { (value: String?, errorInfo: Task.ErrorInfo?) -> Void in + + }.then { value, errorInfo -> Void in XCTAssertEqual(value!, "OK2") XCTAssertTrue(errorInfo == nil) @@ -241,17 +241,17 @@ class SwiftTaskTests: _TestCase // MARK: - Reject //-------------------------------------------------- - func testReject_catch() + func testReject_failure() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { reject("ERROR") } - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "ERROR") XCTAssertFalse(isCancelled) @@ -263,21 +263,21 @@ class SwiftTaskTests: _TestCase self.wait() } - func testReject_then_catch() + func testReject_success_failure() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { reject("ERROR") } - }.then { (value: String) -> Void in + }.success { value -> Void in XCTFail("Should never reach here.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "ERROR") XCTAssertFalse(isCancelled) @@ -289,26 +289,26 @@ class SwiftTaskTests: _TestCase self.wait() } - func testReject_catch_then() + func testReject_failure_success() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { reject("ERROR") } - }.catch { (error: ErrorString?, isCancelled: Bool) -> String in + }.failure { error, isCancelled -> String in XCTAssertEqual(error!, "ERROR") XCTAssertFalse(isCancelled) return "RECOVERY" - }.then { (value: String) -> Void in + }.success { value -> Void in - XCTAssertEqual(value, "RECOVERY", "value should be derived from 2nd catching task.") + XCTAssertEqual(value, "RECOVERY", "value should be derived from 2nd failure task.") expect.fulfill() @@ -317,22 +317,22 @@ class SwiftTaskTests: _TestCase self.wait() } - func testReject_catchTaskFulfill() + func testReject_failureTaskFulfill() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { reject("ERROR") } - }.catch { (error: ErrorString?, isCancelled: Bool) -> Task in + }.failure { error, isCancelled -> Task in XCTAssertEqual(error!, "ERROR") XCTAssertFalse(isCancelled) - return Task { (progress, fulfill, reject, configure) in + return Task { progress, fulfill, reject, configure in self.perform { fulfill("RECOVERY") @@ -340,7 +340,7 @@ class SwiftTaskTests: _TestCase } - }.then { (value: String) -> Void in + }.success { value -> Void in XCTAssertEqual(value, "RECOVERY") @@ -350,22 +350,22 @@ class SwiftTaskTests: _TestCase self.wait() } - func testReject_catchTaskReject() + func testReject_failureTaskReject() { var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { reject("ERROR") } - }.catch { (error: ErrorString?, isCancelled: Bool) -> Task in + }.failure { error, isCancelled -> Task in XCTAssertEqual(error!, "ERROR") XCTAssertFalse(isCancelled) - return Task { (progress, fulfill, reject, configure) in + return Task { progress, fulfill, reject, configure in self.perform { reject("ERROR2") @@ -373,11 +373,11 @@ class SwiftTaskTests: _TestCase } - }.then { (value: String) -> Void in + }.success { value -> Void in XCTFail("Should never reach here.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "ERROR2") XCTAssertFalse(isCancelled) @@ -389,19 +389,19 @@ class SwiftTaskTests: _TestCase self.wait() } - func testReject_then2() + func testReject_then() { typealias Task = SwiftTask.Task var expect = self.expectationWithDescription(__FUNCTION__) - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { reject("ERROR") } - }.then { (value: String?, errorInfo: Task.ErrorInfo?) -> String in + }.then { value, errorInfo -> String in // thenClosure can handle both fulfilled & rejected XCTAssertTrue(value == nil) @@ -410,7 +410,7 @@ class SwiftTaskTests: _TestCase return "OK" - }.then { (value: String?, errorInfo: Task.ErrorInfo?) -> Void in + }.then { value, errorInfo -> Void in XCTAssertEqual(value!, "OK") XCTAssertTrue(errorInfo == nil) @@ -430,27 +430,24 @@ class SwiftTaskTests: _TestCase var expect = self.expectationWithDescription(__FUNCTION__) var progressCount = 0 - Task { (progress, fulfill, reject, configure) in + Task { progress, fulfill, reject, configure in self.perform { - progress(0.0) - progress(0.2) progress(0.5) - progress(0.8) progress(1.0) fulfill("OK") } - }.progress { (progress: Float) in + }.progress { oldProgress, newProgress in progressCount++ if self.isAsync { // 0.0 <= progress <= 1.0 -// XCTAssertGreaterThanOrEqual(progress, 0) // TODO: Xcode6.1-GM bug -// XCTAssertLessThanOrEqual(progress, 1) // TODO: Xcode6.1-GM bug - XCTAssertTrue(progress >= 0) - XCTAssertTrue(progress <= 1) +// XCTAssertGreaterThanOrEqual(newProgress, 0) // TODO: Xcode6.1-GM bug +// XCTAssertLessThanOrEqual(newProgress, 1) // TODO: Xcode6.1-GM bug + XCTAssertTrue(newProgress >= 0) + XCTAssertTrue(newProgress <= 1) // 1 <= progressCount <= 5 XCTAssertGreaterThanOrEqual(progressCount, 1) @@ -460,51 +457,7 @@ class SwiftTaskTests: _TestCase XCTFail("When isAsync=false, 1st task closure is already performed before registering this progress closure, so this closure should not be reached.") } - }.then { (value: String) -> Void in - - XCTAssertEqual(value, "OK") - - if self.isAsync { - XCTAssertEqual(progressCount, 5) - } - else { - XCTAssertLessThanOrEqual(progressCount, 0, "progressCount should be 0 because progress closure should not be invoked when isAsync=false") - } - - expect.fulfill() - - } - - self.wait() - } - - func testProgressTuple() - { - var expect = self.expectationWithDescription(__FUNCTION__) - var progressCount = 0 - - Task { (progress, fulfill, reject, configure) in - - self.perform { - progress(0.5) - progress(1.0) - fulfill("OK") - } - - }.progress { (oldValue: Float?, newValue: Float) in // progressTupleClosure - - progressCount++ - - if self.isAsync { - if !((oldValue == nil && newValue == 0.5) || (oldValue! == 0.5 && newValue == 1.0)) { - XCTFail("Invalid progressTuple (\(oldValue), \(newValue)).") - } - } - else { - XCTFail("When isAsync=false, 1st task closure is already performed before registering this progress closure, so this closure should not be reached.") - } - - }.then { (value: String) -> Void in + }.success { (value: String) -> Void in XCTAssertEqual(value, "OK") @@ -516,7 +469,7 @@ class SwiftTaskTests: _TestCase } expect.fulfill() - + } self.wait() @@ -531,7 +484,7 @@ class SwiftTaskTests: _TestCase typealias _InterruptableTask = Task func _interruptableTask() -> _InterruptableTask { - return Task { (progress, fulfill, reject, configure) in + return Task { progress, fulfill, reject, configure in // NOTE: not a good flag, watch out for race condition! var isCancelled = false @@ -585,26 +538,26 @@ class SwiftTaskTests: _TestCase var progressCount = 0 let task = self._interruptableTask() - - task.progress { (progress: Float) in + + task.progress { oldProgress, newProgress in progressCount++ // 0.0 <= progress <= 0.5 (not 1.0) -// XCTAssertGreaterThanOrEqual(progress, 0) // TODO: Xcode6.1-GM bug -// XCTAssertLessThanOrEqual(progress, 0.5) // TODO: Xcode6.1-GM bug - XCTAssertTrue(progress >= 0) - XCTAssertTrue(progress <= 0.5) +// XCTAssertGreaterThanOrEqual(newProgress, 0) // TODO: Xcode6.1-GM bug +// XCTAssertLessThanOrEqual(newProgress, 0.5) // TODO: Xcode6.1-GM bug + XCTAssertTrue(newProgress >= 0) + XCTAssertTrue(newProgress <= 0.5) // 1 <= progressCount <= 3 (not 5) XCTAssertGreaterThanOrEqual(progressCount, 1) XCTAssertLessThanOrEqual(progressCount, 3, "progressCount should be stopped to 3 instead of 5 because of cancellation.") - }.then { (value: String) -> Void in + }.success { value -> Void in XCTFail("Should never reach here because of cancellation.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "I get bored.") XCTAssertTrue(isCancelled) @@ -635,14 +588,14 @@ class SwiftTaskTests: _TestCase var task2: _InterruptableTask? = nil - let task3 = task1.then { (value: String) -> _InterruptableTask in + let task3 = task1.then { value, errorInfo -> _InterruptableTask in task2 = self._interruptableTask() return task2! } - task3.catch { (error: ErrorString?, isCancelled: Bool) -> String in + task3.failure { error, isCancelled -> String in XCTAssertEqual(error!, "I get bored.") XCTAssertTrue(isCancelled) @@ -681,12 +634,12 @@ class SwiftTaskTests: _TestCase let task = self._interruptableTask() - task.progress { (progress: Float) in + task.progress { _ in progressCount++ return - }.then { (value: String) -> Void in + }.success { value -> Void in XCTAssertEqual(value, "OK") XCTAssertEqual(progressCount, 5) @@ -724,7 +677,7 @@ class SwiftTaskTests: _TestCase //-------------------------------------------------- /// all fulfilled test - func testAll_then() + func testAll_success() { // NOTE: this is async test if !self.isAsync { return } @@ -737,7 +690,7 @@ class SwiftTaskTests: _TestCase for i in 0..<10 { // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in Async.background(after: 0.1) { Async.main { progress(0.1) } @@ -756,19 +709,19 @@ class SwiftTaskTests: _TestCase // For tracking each task's progress, you simply call `task.progress` // instead of `Task.all(tasks).progress`. // - task.progress { (progress: Any) in - println("each progress = \(progress)") + task.progress { oldProgress, newProgress in + println("each progress = \(newProgress)") return } tasks.append(task) } - Task.all(tasks).progress { (progress: Task.BulkProgress) in + Task.all(tasks).progress { (oldProgress: Task.BulkProgress?, newProgress: Task.BulkProgress) in - println("all progress = \(progress.completedCount) / \(progress.totalCount)") + println("all progress = \(newProgress.completedCount) / \(newProgress.totalCount)") - }.then { (values: [String]) -> Void in + }.success { values -> Void in for i in 0.. Void in + Task.all(tasks).success { values -> Void in XCTFail("Should never reach here because of Task.all failure.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "ERROR", "Task.all non-cancelled error returns 1st-errored object (spec).") expect.fulfill() @@ -843,7 +796,7 @@ class SwiftTaskTests: _TestCase for i in 0..<10 { // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in var isCancelled = false @@ -866,11 +819,11 @@ class SwiftTaskTests: _TestCase let groupedTask = Task.all(tasks) - groupedTask.then { (values: [String]) -> Void in + groupedTask.success { values -> Void in XCTFail("Should never reach here.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "Cancel") XCTAssertTrue(isCancelled) @@ -900,7 +853,7 @@ class SwiftTaskTests: _TestCase for i in 0..<10 { // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in var isPaused = false @@ -927,7 +880,7 @@ class SwiftTaskTests: _TestCase let groupedTask = Task.all(tasks) - groupedTask.then { (values: [String]) -> Void in + groupedTask.success { values -> Void in for i in 0.. Void in + Task.any(tasks).success { value -> Void in XCTAssertEqual(value, "OK 5") @@ -1004,7 +957,7 @@ class SwiftTaskTests: _TestCase } /// all rejected test - func testAny_catch() + func testAny_failure() { // NOTE: this is async test if !self.isAsync { return } @@ -1017,7 +970,7 @@ class SwiftTaskTests: _TestCase for i in 0..<10 { // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in Async.background(after: 0.1) { Async.main { reject("Failed \(i)") } @@ -1030,11 +983,11 @@ class SwiftTaskTests: _TestCase tasks.append(task) } - Task.any(tasks).then { (value: String) -> Void in + Task.any(tasks).success { value -> Void in XCTFail("Should never reach here.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertTrue(error == nil, "Task.any non-cancelled error returns nil (spec).") XCTAssertFalse(isCancelled) @@ -1058,7 +1011,7 @@ class SwiftTaskTests: _TestCase for i in 0..<10 { // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in var isCancelled = false @@ -1081,11 +1034,11 @@ class SwiftTaskTests: _TestCase let groupedTask = Task.any(tasks) - groupedTask.then { (value: String) -> Void in + groupedTask.success { value -> Void in XCTFail("Should never reach here.") - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTAssertEqual(error!, "Cancel") XCTAssertTrue(isCancelled) @@ -1115,7 +1068,7 @@ class SwiftTaskTests: _TestCase for i in 0..<10 { // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in var isPaused = false @@ -1143,7 +1096,7 @@ class SwiftTaskTests: _TestCase let groupedTask = Task.any(tasks) - groupedTask.then { (value: String) -> Void in + groupedTask.success { value -> Void in XCTAssertTrue(value.hasPrefix("OK")) expect.fulfill() @@ -1172,7 +1125,7 @@ class SwiftTaskTests: _TestCase //-------------------------------------------------- /// some fulfilled test - func testSome_then() + func testSome_success() { // NOTE: this is async test if !self.isAsync { return } @@ -1185,7 +1138,7 @@ class SwiftTaskTests: _TestCase for i in 0..<10 { // define task - let task = Task { (progress, fulfill, reject, configure) in + let task = Task { progress, fulfill, reject, configure in Async.main(after: 0.1) { @@ -1203,7 +1156,7 @@ class SwiftTaskTests: _TestCase tasks.append(task) } - Task.some(tasks).then { (values: [String]) -> Void in + Task.some(tasks).success { values -> Void in XCTAssertEqual(values.count, 2) XCTAssertEqual(values[0], "OK 3") @@ -1211,7 +1164,7 @@ class SwiftTaskTests: _TestCase expect.fulfill() - }.catch { (error: ErrorString?, isCancelled: Bool) -> Void in + }.failure { error, isCancelled -> Void in XCTFail("Should never reach here because Task.some() will never reject internally.")