Promise + 进度 + 暂停 + 取消 + 重试,用于 Swift。
请参阅 ReactKit Wiki 页面。
// define task
let task = Task<Float, String, NSError> { progress, fulfill, reject, configure in
player.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()
注意,player
具有以下方法,可与SwiftTask
很好地配合使用
doSomethingWithProgress(_:completion:)
(进度回调为可选)pause()
(可选)resume()
(可选)cancel()
(可选)一个最好的例子是Alamofire(网络库),如下所示。
typealias Progress = (bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
typealias AlamoFireTask = Task<Progress, String, NSError>
// define task
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) 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) in
println("\(newProgress.bytesWritten)")
println("\(newProgress.totalBytesWritten)")
println("\(newProgress.totalBytesExpectedToWrite)")
}.then { (value: String?, errorInfo: AlamoFireTask.ErrorInfo?) -> Void in
// do something with fulfilled value or rejected errorInfo
}
Task
可以通过使用retry()
方法重试多次。例如,task.retry(n)
如果task
持续被拒绝,将最多重试n
次(总尝试次数为n+1
),而task.retry(0)
显然与没有重试的task
本身相同。
这个特性对于不稳定的任务非常有用,例如网络连接。通过在SwiftTask
方面实现retryable,不再需要在player
(内部逻辑)类中编写相似的代码。
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.
}
更多例子请参阅 XCTest 案例文档。
在initClosure
中定义您的task
。
let task = Task<Float, NSString?, NSError> { progress, fulfill, reject, configure in
player.doSomethingWithCompletion { (value: NSString?, error: NSError?) in
if error == nil {
fulfill(value)
}
else {
reject(error)
}
}
}
为了通过 then()
/success()
/failure()
管道未来的 task.value
或 task.errorInfo
(一个包含 (error: Error?, isCancelled: Bool)
的元组),), 您必须在 initClosure
中调用 fulfill(value)
和/或 reject(error)
。
可选地,在调用 fulfill
/reject
之前,您可以多次调用 progress(progressValue)
来传输 progressValue
到 initClosure
之外,通知给 task
本身。
为了将 pause
/resume
/cancel
功能添加到您的 task
中,请使用 configure
来包裹原始功能。
// 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 { (oldProgress: Progress?, newProgress: Progress) in
println(newProgress)
return
}.success { ... }
task.progress(progressClosure)
会将 progressClosure
添加为观察旧的/新的 progressValue
,这些值是从之前的 initClosure
内部通知的。此方法将返回 相同任务,因此它对于与随后的 then
/success
/failure
连接非常有用。
task.then(thenClosure)
将返回一个新的任务,其中当 task
要么是 fulfilled 要么是 rejected 时将调用 thenClosure
。
此情况类似于 JavaScript 的 promise.then(onFulfilled, onRejected)
。
thenClosure
可以是两种类型的闭包形式
thenClosure: (Value?, ErrorInfo?) -> Value2
(流:task => newTask)
// 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"
}
thenClosure: (Value?, ErrorInfo?) -> Task
(流:task => task2 => newTask)
// let task will be fulfilled with value "Hello"
task.then { (value: String?, errorInfo: ErrorInfo?) -> Task<Float, String, NSError> 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"
}
类似于 then()
方法,task.success(successClosure)
将返回一个新任务,但这次,仅在任务 仅 fulfilled 时调用 successClosure
。
这种情况类似于 JavaScript 的 promise.then(onFulfilled)
。
// 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"
}
与 success()
正好相反,task.failure(failureClosure)
将返回一个新任务,其中 failureClosure
将在任务 仅 rejected/cancelled 时调用。
这种情况类似于 JavaScript 的 promise.then(undefined, onRejected)
或 promise.catch(onRejected)
。
// 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.all(tasks)
是一个新任务,该任务同时执行所有 tasks
并将
Task.any(tasks)
是 Task.all(tasks)
的对立面,它将在
Task.some(tasks)
是一个执行所有 tasks
而不内部 rejected 的新任务,并以给定的 tasks
的 fulfilled 值来 fulfiling。请注意,即使在所有 tasks
都被 rejected 的情况下,这个新任务也需要以空的值数组被 fulfiling。