Skip to content

Ver 2.0.0: Rename then/catch to then/success/failure. #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 18, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 75 additions & 90 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@ 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

### Basic

```swift
// define task
let task = Task<Float, String, NSError> { (progress, fulfill, reject, configure) in
let task = Task<Float, String, NSError> { progress, fulfill, reject, configure in

player.doSomethingWithProgress({ (progressValue: Float) in
progress(progressValue) // optional
Expand All @@ -38,10 +45,10 @@ let task = Task<Float, String, NSError> { (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
}

Expand All @@ -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<Progress, String, NSError>

// define task
let task = Task<Progress, String, NSError> { (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)
Expand All @@ -88,15 +96,15 @@ let task = Task<Progress, String, NSError> { (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
}
```

Expand All @@ -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<Float, NSString?, NSError> { (progress, fulfill, reject, configure) in
let task = Task<Float, NSString?, NSError> { progress, fulfill, reject, configure in

player.doSomethingWithCompletion { (value: NSString?, error: NSError?) in
if error == nil {
Expand All @@ -123,9 +131,9 @@ let task = Task<Float, NSString?, NSError> { (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.

Expand All @@ -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<Float, String, NSError> 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<Float, String, NSError> in
task.onComplete { (value: String?, errorInfo: ErrorInfo?) -> Task<Float, String, NSError> 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
}
Expand All @@ -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
Expand Down
Loading