在另一个发布者的地图中使用发布者的结果
Use result of publisher in map of another publisher
例如,我有一个基本的发布值,例如
@Published var value: String
我想验证我表单的这个值来给我的用户一个输出。为此,我将在我的 MVVM 项目中使用 Combine。
现在需要根据我的 REST API 验证这种类型的值。对于我的 REST API,我已经有了一种方法来获得我喜欢的结果 getFirstMailboxRedirectFromAPI
,其中 returns AnyPublisher<MailboxAPIResponse, APIError>
。 MailboxAPIResponse 是 api 响应的可解码对象。因此,如果我只想显示结果,我会创建一个带有 .sink
的订阅者,将结果添加到将在视图中显示的变量。到目前为止还不错。现在我的问题:
如第一部分所述,我的值已经是一个 Publisher(因为 @Published),我可以在其中做一些 .map
的验证工作,如果一切正常,则返回 true 或 false .
因此,为了验证我发布的值,我需要调用其他使用 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 会给我结果,然后 returns 一个布尔值,如果它是存在与否。
如何嵌套多个发布者并在我的发布值发布者中使用 API 发布者的结果?
我简化了一点,但关键要点是 1) 如果您希望重新启动操作,请使用 switchToLatest 来展平发布者的发布者(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()
}
}
例如,我有一个基本的发布值,例如
@Published var value: String
我想验证我表单的这个值来给我的用户一个输出。为此,我将在我的 MVVM 项目中使用 Combine。
现在需要根据我的 REST API 验证这种类型的值。对于我的 REST API,我已经有了一种方法来获得我喜欢的结果 getFirstMailboxRedirectFromAPI
,其中 returns AnyPublisher<MailboxAPIResponse, APIError>
。 MailboxAPIResponse 是 api 响应的可解码对象。因此,如果我只想显示结果,我会创建一个带有 .sink
的订阅者,将结果添加到将在视图中显示的变量。到目前为止还不错。现在我的问题:
如第一部分所述,我的值已经是一个 Publisher(因为 @Published),我可以在其中做一些 .map
的验证工作,如果一切正常,则返回 true 或 false .
因此,为了验证我发布的值,我需要调用其他使用 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 会给我结果,然后 returns 一个布尔值,如果它是存在与否。
如何嵌套多个发布者并在我的发布值发布者中使用 API 发布者的结果?
我简化了一点,但关键要点是 1) 如果您希望重新启动操作,请使用 switchToLatest 来展平发布者的发布者(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()
}
}