Swift 如何使用Combine+;复制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

我曾在一个项目中成功地使用PromiseKit,直到Xcode 11 betas打破PK v7。为了减少外部依赖,我决定放弃PromiseKit。处理链式异步代码的最佳替代方案似乎是使用新的Combine框架

我正在努力使用Combine复制简单的PK语法

例如简单PromiseKit链接异步调用语法

getAccessCodeFromSyncProvider。然后{startSync中的accessCode(accessCode)}。然后{popToRootViewController}。catch{handleError(error)}
我明白:

async/await的Swift标准库实现可以解决这个问题(async/await目前还不存在,尽管有很多人谈论和参与)

我可以使用信号量进行复制(容易出错?)

flatMap可用于连锁期货

我想要的异步代码应该能够按需调用,因为它涉及确保用户登录。我正在努力解决两个概念问题

  • 如果我将期货包装在一个方法中,使用
    sink
    来处理结果,那么在订阅服务器被
    sink
    调用之前,该方法似乎超出了范围

  • 由于Futures只执行一次,我担心如果我多次调用该方法,我只会从第一次调用中得到旧的、过时的结果。为了解决这个问题,也许我会使用PassthroughSubject?这允许按需调用发布服务器

  • 问题:

  • 我是否必须保留网站之外的所有发布者和订阅者 调用方法
  • 如何使用Swift标准库复制简单的链式异步,然后将其嵌入Swift实例方法中?我可以按需调用以从顶部重新启动链式异步调用
  • //如何使用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")
        }
    }