【问题标题】:Use result of publisher in map of another publisher在另一个发布者的地图中使用发布者的结果
【发布时间】:2021-04-24 02:25:38
【问题描述】:

例如,我有一个基本的已发布值,例如

@Published var value: String

我想验证我的表单的这个值给我的用户一个输出。为此,我将在我的 MVVM 项目中使用 Combine。

现在需要根据我的 REST API 验证这种类型的值。对于我的 REST API,我已经有一种方法来获取我的类似 getFirstMailboxRedirectFromAPI 的结果,它返回 AnyPublisher<MailboxAPIResponse, APIError>。 MailboxAPIResponse 是 api 响应的可解码对象。因此,如果我只想显示结果,我会使用.sink 创建一个订阅者,并将结果添加到将显示在视图中的变量中。到目前为止这么好。现在我的问题:

如第一部分所述,我的值已经是一个发布者(因为@Published),我可以在其中做一些.map 的东西来验证它,如果一切正常,则返回真或假。

因此,为了验证我发布的值,我需要调用我的其他发布者,它使用 API 来检查该值是否已经存在。但我不知道这应该如何工作。

到目前为止,这是我的代码,但这不起作用。但这向您展示了我的想法应该如何工作。

private var isMailboxRedirectNameAvailablePublisher: AnyPublisher<Bool, Never> {
    $mailboxRedirectName
        .debounce(for: 0.5, scheduler: RunLoop.main)
        .setFailureType(to: Error.self)
        .flatMap { name in
            self.getFirstMailboxRedirectFromAPI(from: name, and: self.domainName)
                .map { apiResponse in
                    return apiResponse.response.data.count == 0
                }
        }
        .eraseToAnyPublisher()
}

所以结果发布者应该使用redirectName来调用API,如果邮箱已经存在,API会给我结果,然后返回一个布尔值,如果它存在与否。

如何嵌套多个发布者并在我的发布值发布者中使用 API 发布者的结果?

【问题讨论】:

    标签: swift mvvm combine flatmap publisher


    【解决方案1】:

    我稍微简化了一点,但关键要点是 1) 如果您希望重新启动操作,请使用 switchToLatest 来展平 Publisher 的 Publisher(flatMap 是一个合并,因此事件可能会乱序到达)。 2)您需要处理失败类型并确保内部发布者永远不会失败,否则外部发布者也将完成。

    final class M: ObservableObject {
      @Published var mailboxRedirectName: String = ""
      private var isMailboxRedirectNameAvailablePublisher: AnyPublisher<Bool, Never> {
          $mailboxRedirectName
            .debounce(for: 0.5, scheduler: DispatchQueue.main)
              .map { [weak self] name -> AnyPublisher<Bool, Never> in
                guard let self = self else { return Just(false).eraseToAnyPublisher() }
                return self
                  .getFirstMailboxRedirectFromAPI(from: name)
                  .replaceError(with: false)
                  .eraseToAnyPublisher()
              }
              .switchToLatest()
              .eraseToAnyPublisher()
      }
    
      func getFirstMailboxRedirectFromAPI(from name: String) -> AnyPublisher<Bool, Error> {
        Just(true).setFailureType(to: Error.self).eraseToAnyPublisher()
      }
    }
    

    【讨论】:

    • 谢谢!但是为什么我必须这样做呢?
    猜你喜欢
    • 2019-11-30
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 2020-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多