Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ReactKit/SwiftTask
Promise + progress + pause + cancel + retry for Swift.
https://github.com/ReactKit/SwiftTask
Last synced: 8 days ago
JSON representation
Promise + progress + pause + cancel + retry for Swift.
- Host: GitHub
- URL: https://github.com/ReactKit/SwiftTask
- Owner: ReactKit
- License: mit
- Created: 2014-08-23T13:39:12.000Z (over 10 years ago)
- Default Branch: swift/4.0
- Last Pushed: 2019-04-15T03:23:50.000Z (over 5 years ago)
- Last Synced: 2024-10-29T17:56:18.600Z (about 1 month ago)
- Language: Swift
- Homepage:
- Size: 561 KB
- Stars: 1,934
- Watchers: 74
- Forks: 176
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-ios - SwiftTask - Promise + progress + pause + cancel + retry for Swift. (EventBus / Getting Started)
- awesome-swift - SwiftTask - Promise + progress + pause + cancel, using SwiftState (state machine). (Extensions)
- awesome-ios-star - SwiftTask - Promise + progress + pause + cancel + retry for Swift. (EventBus / Getting Started)
README
SwiftTask [![Circle CI](https://circleci.com/gh/ReactKit/SwiftTask/tree/swift%2F2.0.svg?style=svg)](https://circleci.com/gh/ReactKit/SwiftTask/tree/swift%2F2.0)
=========[Promise](http://www.html5rocks.com/en/tutorials/es6/promises/) + progress + pause + cancel + retry for Swift.
![SwiftTask](Screenshots/diagram.png)
## How to install
See [ReactKit Wiki page](https://github.com/ReactKit/ReactKit/wiki/How-to-install).
## Example
### Basic
```swift
// define task
let task = Task { progress, fulfill, reject, configure inplayer.doSomethingWithProgress({ (progressValue: Float) in
progress(progressValue) // optional
}, completion: { (value: NSData?, error: NSError?) in
if error == nil {
fulfill("OK")
}
else {
reject(error)
}
})// pause/resume/cancel configuration (optional)
configure.pause = { [weak player] in
player?.pause()
}
configure.resume = { [weak player] in
player?.resume()
}
configure.cancel = { [weak player] in
player?.cancel()
}}
// set success & failure
task.success { (value: String) -> Void in
// do something with fulfilled value
}.failure { (error: NSError?, isCancelled: Bool) -> Void in
// do something with rejected error
}// you can call configured operations outside of Task-definition
task.pause()
task.resume()
task.cancel()
```Notice that `player` has following methods, which will work nicely with `SwiftTask`:
- `doSomethingWithProgress(_:completion:)` (progress callback as optional)
- `pause()` (optional)
- `resume()` (optional)
- `cancel()` (optional)One of the best example would be [Alamofire](https://github.com/Alamofire/Alamofire) (networking library)
as seen below.### Using [Alamofire](https://github.com/Alamofire/Alamofire)
```swift
typealias Progress = (bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
typealias AlamoFireTask = Task// define task
let task = AlamoFireTask { progress, fulfill, reject, configure inAlamofire.download(.GET, "http://httpbin.org/stream/100", destination: somewhere)
.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite inprogress((bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) as Progress)
}.response { request, response, data, error in
if let error = error {
reject(error)
return
}fulfill("OK")
}
return
}// set progress & then
task.progress { (oldProgress: Progress?, newProgress: Progress) inprintln("\(newProgress.bytesWritten)")
println("\(newProgress.totalBytesWritten)")
println("\(newProgress.totalBytesExpectedToWrite)")}.then { (value: String?, errorInfo: AlamoFireTask.ErrorInfo?) -> Void in
// do something with fulfilled value or rejected errorInfo
}
```### Retry-able
`Task` can retry for multiple times by using `retry()` method.
For example, `task.retry(n)` will retry at most `n` times (total tries = `n+1`) if `task` keeps rejected, and `task.retry(0)` is obviously same as `task` itself having no retries.This feature is extremely useful for unstable tasks e.g. network connection.
By implementing *retryable* from `SwiftTask`'s side, similar code is no longer needed for `player` (inner logic) class.```swift
task.retry(2).progress { ... }.success { ...
// this closure will be called even when task is rejected for 1st & 2nd try
// but finally fulfilled in 3rd try.
}
```For more examples, please see XCTest cases.
## API Reference
### Task.init(initClosure:)
Define your `task` inside `initClosure`.
```swift
let task = Task { progress, fulfill, reject, configure inplayer.doSomethingWithCompletion { (value: NSString?, error: NSError?) in
if error == nil {
fulfill(value)
}
else {
reject(error)
}
}
}
```In order to pipeline future `task.value` or `task.errorInfo` (tuple of `(error: Error?, isCancelled: Bool)`) via `then()`/`success()`/`failure()`, 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 `initClosure`, notifying it to `task` itself.
To add `pause`/`resume`/`cancel` functionality to your `task`, use `configure` to wrap up the original one.
```swift
// NOTE: use weak to let task NOT CAPTURE player via configure
configure.pause = { [weak player] in
player?.pause()
}
configure.resume = { [weak player] in
player?.resume()
}
configure.cancel = { [weak player] in
player?.cancel()
}
```### task.progress(_ progressClosure:) -> task
```swift
task.progress { (oldProgress: Progress?, newProgress: Progress) in
println(newProgress)
return
}.success { ... }
````task.progress(progressClosure)` will add `progressClosure` to observe old/new `progressValue` which is notified from inside previous `initClosure`. This method will return **same task**, so it is useful to chain with forthcoming `then`/`success`/`failure`.
### task.then(_ thenClosure:) -> newTask
`task.then(thenClosure)` will return a new task where `thenClosure` will be invoked when `task` is either **fulfilled** or **rejected**.
This case is similar to JavaScript's `promise.then(onFulfilled, onRejected)`.
`thenClosure` can be two types of closure form:
1. `thenClosure: (Value?, ErrorInfo?) -> Value2` (flow: *task => newTask*)
```swift
// let task will be fulfilled with value "Hello"task.then { (value: String?, errorInfo: ErrorInfo?) -> String in
// nil-check to find out whether task is fulfilled or rejected
if errorInfo == nil {
return "\(value!) World"
}
else {
return "\(value!) Error"
}
}.success { (value: String) -> Void in
println("\(value)") // Hello World
return"
}
```2. `thenClosure: (Value?, ErrorInfo?) -> Task` (flow: *task => task2 => newTask*)
```swift
// let task will be fulfilled with value "Hello"task.then { (value: String?, errorInfo: ErrorInfo?) -> Task in
if errorInfo == nil {
// let task2 will be fulfilled with value "\(value!) Swift"
let task2 = ...
return task2
}
else {
return someOtherTask
}
}.success { (value: String) -> Void in
println("\(value)") // Hello Swift
return"
}
```### task.success(_ successClosure:) -> newTask
Similar to `then()` method, `task.success(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.success { (value: String) -> String in
return "\(value) World"
}.success { (value: String) -> Void in
println("\(value)") // Hello World
return"
}
```### task.failure(_ failureClosure:) -> newTask
Just the opposite of `success()`, `task.failure(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
// let task will be rejected with error "Oh My God"task.success { (value: String) -> Void in
println("\(value)") // never reaches here
return
}.failure { (error: NSError?, isCancelled: Bool) -> Void in
println("\(error!)") // Oh My God
return
}
```### task.try(_ tryCount:) -> newTask
See [Retry-able section](#retry-able).
### Task.all(_ tasks:) -> newTask
`Task.all(tasks)` is a new task that performs all `tasks` simultaneously and will be:
- 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 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 be fulfilled with empty value-array, even though all `tasks` are rejected.**
## Related Articles
- [SwiftTask(Promise拡張)を使う - Qiita](http://qiita.com/inamiy/items/0756339aee35849384c3) (Japanese, ver 1.0.0)
## Licence
[MIT](LICENSE)