首页 > 解决方案 > Swift Combine 完成按钮点击

问题描述

我有一个连接到PassthroughSubject触发网络负载的按钮。我遇到的问题是,如果网络请求失败(或飞行前验证失败),PassthroughSubject则完成:

private let createListSubject = PassthroughSubject<Void, Never>()

当点击按钮时,我会通过 向该主题发送一个新事件send(())

// Later on, in some function I set up the subject
    private func setupCreateListSubject() {
        self.createListSubject
            .combineLatest(self.$listName, self.$selectedClients)
            .tryMap { [weak self] (_, listName, selectedClients) -> (String, [String]) in
                let clients = Array(selectedClients)
                try self?.validate(listName: listName, selectedClients: clients)
                return (listName, clients)
            }
            .flatMap { [clientListCreator] (listName, selectedClients) -> AnyPublisher<Result<ClientListMembersDisplayable, Error>, Error> in
                return clientListCreator.createClientList(listName: listName, listMemberIds: selectedClients)
            }
            .catch { error  in
                return Future<Result<ClientListMembersDisplayable, Error>, Error> { // <-- One of the problems is that Future completes after 1 event
                    $0(.success(.failure(error)))
                }
            }
            .sink(receiveCompletion: { [weak self] completion in
                switch completion {
                case .failure(let error):
                    self?.errorAlertContext = AlertContext(title: error.localizedDescription)
                case .finished:
                    break
                }
            }, receiveValue: { [weak self] result in
                switch result {
                case .failure(let error):
                    self?.errorAlertContext = AlertContext(title: error.localizedDescription)
                case .success:
                    self?.errorAlertContext = nil
                }
            }).store(in: &self.disposeBag)
    }

有两个问题:

我可以用 a 解决这两个问题,replaceError但我想要的是将发布者的错误转换为带有Result错误的成功,并且createListSubject不接收任何完成事件(因为用户将来仍希望点击该按钮。

什么是组合方式来做到这一点?我认为我想要的是类似于replaceError()但收到旧错误并返回成功结果的东西。

标签: iosswiftswiftuireactivecombine

解决方案


该模式是将其包装在 a 中flatMap,因此您可以通过生成一个新的发布者来处理每个值,该发布者的输出为Result<..., Error>和失败Never

createListSubject
   .combineLatest(self.$listName, self.$selectedClients)
   .flatMap { [weak self] (_, listName, selectedClients) -> AnyPublisher<Result< ClientListMembersDisplayable, Error>, Never> in
        
      Just(())
      .tryMap { 
         try self?.validate(listName: listName, selectedClients: selectedClients)
      }
      .flatMap {
         // I'm assuming this returns AnyPublisher<Result<ClientListMembersDisplayable, Error>, Error>
         clientListCreator.createClientList(listName: listName, listMemberIds: selectedClients)
      }
      .catch { err -> AnyPublisher<Result<ClientListMembersDisplayable, Error>, Never>
         Just(.failure(err))
      }
      .eraseToAnyPublisher()
   }
   .sink (...)
   .store(in: &self.disposeBag)

推荐阅读