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。