Swift 如何使用Combine+;复制PromiseKit样式的链式异步流;敏捷的
我曾在一个项目中成功地使用PromiseKit,直到Xcode 11 betas打破PK v7。为了减少外部依赖,我决定放弃PromiseKit。处理链式异步代码的最佳替代方案似乎是使用新的Combine框架 我正在努力使用Combine复制简单的PK语法 例如简单PromiseKit链接异步调用语法Swift 如何使用Combine+;复制PromiseKit样式的链式异步流;敏捷的,swift,asynchronous,combine,Swift,Asynchronous,Combine,我曾在一个项目中成功地使用PromiseKit,直到Xcode 11 betas打破PK v7。为了减少外部依赖,我决定放弃PromiseKit。处理链式异步代码的最佳替代方案似乎是使用新的Combine框架 我正在努力使用Combine复制简单的PK语法 例如简单PromiseKit链接异步调用语法 getAccessCodeFromSyncProvider。然后{startSync中的accessCode(accessCode)}。然后{popToRootViewController}。ca
getAccessCodeFromSyncProvider。然后{startSync中的accessCode(accessCode)}。然后{popToRootViewController}。catch{handleError(error)}
我明白:
async/await的Swift标准库实现可以解决这个问题(async/await目前还不存在,尽管有很多人谈论和参与)
我可以使用信号量进行复制(容易出错?)
flatMap可用于连锁期货
我想要的异步代码应该能够按需调用,因为它涉及确保用户登录。我正在努力解决两个概念问题
sink
来处理结果,那么在订阅服务器被sink
调用之前,该方法似乎超出了范围
//如何使用Combine完成此操作?
func startSync(){
getAccessCodeFromSyncProvider.then{startSync中的accessCode(accessCode)}.catch{\\handle error here}
}
这并不是对您的整个问题的真正答案-只是关于如何开始使用联合收割机的部分。我将演示如何使用Combine框架链接两个异步操作:
print("start")
Future<Bool,Error> { promise in
delay(3) {
promise(.success(true))
}
}
.handleEvents(receiveOutput: {_ in print("finished 1")})
.flatMap {_ in
Future<Bool,Error> { promise in
delay(3) {
promise(.success(true))
}
}
}
.handleEvents(receiveOutput: {_ in print("finished 2")})
.sink(receiveCompletion: {_ in}, receiveValue: {_ in print("done")})
.store(in:&self.storage) // storage is a persistent Set<AnyCancellable>
您可以看到,我们已经链接了两个异步操作,每个操作都需要3秒钟
我们是怎么做到的?我们从一个Future开始,它必须调用传入的promise
方法,并在完成时将结果作为完成处理程序。之后,我们使用.flatMap
创建另一个未来并将其投入运行,再次做同样的事情
因此,结果并不漂亮(像PromiseKit),但它是一个异步操作链
在合并之前,我们可能已经通过某种操作/操作队列依赖性完成了这项工作,这将很好地工作,但PromiseKit的直接易读性甚至更低
稍微现实一点
说到这里,这里有一个更现实的重写:
var storage = Set<AnyCancellable>()
func async1(_ promise:@escaping (Result<Bool,Error>) -> Void) {
delay(3) {
print("async1")
promise(.success(true))
}
}
func async2(_ promise:@escaping (Result<Bool,Error>) -> Void) {
delay(3) {
print("async2")
promise(.success(true))
}
}
override func viewDidLoad() {
print("start")
Future<Bool,Error> { promise in
self.async1(promise)
}
.flatMap {_ in
Future<Bool,Error> { promise in
self.async2(promise)
}
}
.sink(receiveCompletion: {_ in}, receiveValue: {_ in print("done")})
.store(in:&self.storage) // storage is a persistent Set<AnyCancellable>
}
您可以将此框架用于Swift协同程序,它还可以与Combine-
DispatchQueue.main.start例程{
让未来:未来
让coFuture=future.subscribebecofuture()
让bool=试试coFuture.await()
}
正确,请使用flatMap
链接承诺。在使用PromiseKit时,我养成了回报承诺的习惯,并将其带到联合体(回报期货)
我发现它使代码更容易阅读。下面是马特最后一个推荐的例子:
var storage = Set<AnyCancellable>()
func async1() -> Future<Bool, Error> {
Future { promise in
delay(3) {
print("async1")
promise(.success(true))
}
}
}
func async2() -> Future<Bool, Error> {
Future { promise in
delay(3) {
print("async2")
promise(.success(true))
}
}
}
override func viewDidLoad() {
print("start")
async1()
.flatMap { _ in async2() }
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: {_ in}, receiveValue: {_ in print("done")})
.store(in:&self.storage) // storage is a persistent Set<AnyCancellable>
}
此外,如果您想使用类似PromiseKit的语法,下面是Publisher的一些扩展 我使用它无缝地从PromiseKit切换到项目中的组合
extension Publisher {
func then<T: Publisher>(_ closure: @escaping (Output) -> T) -> Publishers.FlatMap<T, Self>
where T.Failure == Self.Failure {
flatMap(closure)
}
func asVoid() -> Future<Void, Error> {
return Future<Void, Error> { promise in
let box = Box()
let cancellable = self.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
} else if case .finished = completion {
box.cancellable = nil
}
} receiveValue: { value in
promise(.success(()))
}
box.cancellable = cancellable
}
}
@discardableResult
func done(_ handler: @escaping (Output) -> Void) -> Self {
let box = Box()
let cancellable = self.sink(receiveCompletion: {compl in
if case .finished = compl {
box.cancellable = nil
}
}, receiveValue: {
handler($0)
})
box.cancellable = cancellable
return self
}
@discardableResult
func `catch`(_ handler: @escaping (Failure) -> Void) -> Self {
let box = Box()
let cancellable = self.sink(receiveCompletion: { compl in
if case .failure(let failure) = compl {
handler(failure)
} else if case .finished = compl {
box.cancellable = nil
}
}, receiveValue: { _ in })
box.cancellable = cancellable
return self
}
@discardableResult
func finally(_ handler: @escaping () -> Void) -> Self {
let box = Box()
let cancellable = self.sink(receiveCompletion: { compl in
if case .finished = compl {
handler()
box.cancellable = nil
}
}, receiveValue: { _ in })
box.cancellable = cancellable
return self
}
}
fileprivate class Box {
var cancellable: AnyCancellable?
}
扩展发布程序{
func-then(u-closure:@escaping(Output)->T)->publisher.FlatMap
其中T.Failure==自失效{
平面图(闭包)
}
func asVoid()->Future{
回报未来{承诺未来}
设box=box()
让cancelable=self.sink{completion in
如果案例失败(let error)=完成{
承诺(失败(错误))
}否则,如果case.finished=完成{
box.cancelable=nil
}
}receiveValue:{中的值
承诺(.success(()))
}
box.cancelable=可取消
}
}
@可丢弃结果
func done(handler:@escaping(Output)->Void)->Self{
设box=box()
let cancelable=self.sink(接收完成:{compl in
如果case.finished=compl{
box.cancelable=nil
}
},接收值:{
处理程序(0美元)
})
box.cancelable=可取消
回归自我
}
@可丢弃结果
func`catch`(handler:@escaping(Failure)->Void)->Self{
设box=box()
let cancelable=self.sink(接收完成:{compl in
如果案例失败(让失败)=补偿{
处理程序(失败)
}否则,如果case.finished=compl{
box.cancelable=nil
}
},receiveValue:{uIn})
box.cancelable=可取消
回归自我
}
@可丢弃结果
func finally(handler:@escaping()->Void)->Self{
设box=box()
let cancelable=self.sink(接收完成:{compl in
如果case.finished=compl{
handler()
box.cancelable=nil
}
},receiveValue:{uIn})
box.cancelable=可取消
回归自我
}
}
文件专用类框{
var可取消:任何可取消?
}
下面是一个使用示例:
func someSync() {
Future<Bool, Error> { promise in
delay(3) {
promise(.success(true))
}
}
.then { result in
Future<String, Error> { promise in
promise(.success("111"))
}
}
.done { string in
print(string)
}
.catch { err in
print(err.localizedDescription)
}
.finally {
print("Finished chain")
}
}
func someSync(){
未来{
延迟(3){
承诺(.成功(真实))
}
}
。然后{导致
未来{
承诺(.success(“111”))
}
var storage = Set<AnyCancellable>()
func async1() -> Future<Bool, Error> {
Future { promise in
delay(3) {
print("async1")
promise(.success(true))
}
}
}
func async2() -> Future<Bool, Error> {
Future { promise in
delay(3) {
print("async2")
promise(.success(true))
}
}
}
override func viewDidLoad() {
print("start")
async1()
.flatMap { _ in async2() }
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: {_ in}, receiveValue: {_ in print("done")})
.store(in:&self.storage) // storage is a persistent Set<AnyCancellable>
}
func async2() -> AnyPublisher<Bool, Error> {
Future { promise in
delay(3) {
print("async2")
promise(.success(true))
}
}.eraseToAnyPubilsher()
}
extension Publisher {
func then<T: Publisher>(_ closure: @escaping (Output) -> T) -> Publishers.FlatMap<T, Self>
where T.Failure == Self.Failure {
flatMap(closure)
}
func asVoid() -> Future<Void, Error> {
return Future<Void, Error> { promise in
let box = Box()
let cancellable = self.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
} else if case .finished = completion {
box.cancellable = nil
}
} receiveValue: { value in
promise(.success(()))
}
box.cancellable = cancellable
}
}
@discardableResult
func done(_ handler: @escaping (Output) -> Void) -> Self {
let box = Box()
let cancellable = self.sink(receiveCompletion: {compl in
if case .finished = compl {
box.cancellable = nil
}
}, receiveValue: {
handler($0)
})
box.cancellable = cancellable
return self
}
@discardableResult
func `catch`(_ handler: @escaping (Failure) -> Void) -> Self {
let box = Box()
let cancellable = self.sink(receiveCompletion: { compl in
if case .failure(let failure) = compl {
handler(failure)
} else if case .finished = compl {
box.cancellable = nil
}
}, receiveValue: { _ in })
box.cancellable = cancellable
return self
}
@discardableResult
func finally(_ handler: @escaping () -> Void) -> Self {
let box = Box()
let cancellable = self.sink(receiveCompletion: { compl in
if case .finished = compl {
handler()
box.cancellable = nil
}
}, receiveValue: { _ in })
box.cancellable = cancellable
return self
}
}
fileprivate class Box {
var cancellable: AnyCancellable?
}
func someSync() {
Future<Bool, Error> { promise in
delay(3) {
promise(.success(true))
}
}
.then { result in
Future<String, Error> { promise in
promise(.success("111"))
}
}
.done { string in
print(string)
}
.catch { err in
print(err.localizedDescription)
}
.finally {
print("Finished chain")
}
}