我正在与Combine和SwiftUI一起玩我的一个小宠物项目,并随手学习。
这是LoginModel
的当前状态:
public class LoginModel: ObservableObject {
@Published var domain: String = ""
@Published var email: String = ""
@Published var password: String = ""
@Published var isValid: Bool = false
public var didChange = PassthroughSubject<Void, Never>()
var credentialsValidPublisher: AnyPublisher<Bool, Never> {
Publishers.CombineLatest($email, $password)
.receive(on: RunLoop.main)
.map { (email, password) in
let emailValid = String.emailValid(emailString: email) // String extension function
let passwordValid = password.count > 5
return emailValid && passwordValid
}
.breakpointOnError()
.eraseToAnyPublisher()
}
init() {
// This works just fine
_ = credentialsValidPublisher.sink { isValid in
self.isValid = isValid
}
// However this does not work at all
_ = domain
.publisher
.receive(on: RunLoop.main)
.sink { value in
print(value)
}
}
}
根据我目前的理解,现在@Published var foo: String
已经附加了一个Publisher
。并且该人应该能够直接使用它来订阅其更改。
将credentialsValidPublisher
变量更改为此也可以:
var credentialsValidPublisher: AnyPublisher<Bool, Never> {
Publishers.CombineLatest3($domain, $email, $password)
.receive(on: RunLoop.main)
.map { (domain, email, password) in
let domainValid = URL.isValidURL(urlString: domain)
let emailValid = String.emailValid(emailString: email)
let passwordValid = password.count > 5
return domainValid && emailValid && passwordValid
}
.breakpointOnError()
.eraseToAnyPublisher()
}
但这不是我想要的。在我的情况下,我需要一个特殊的Publisher
才能将有效的URL字符串映射到网络请求,然后对当前的服务器执行ping操作,以查看提供的服务器是否在响应。
此外,此模型还通过一堆SwiftUI TextFields连接到SwiftUI视图。 将为我指出正确的方向提供任何帮助。
答案 0 :(得分:0)
所以我想出了办法。
在LoginModel
下的var credentialsValidPublisher: AnyPublisher<Bool, Never>
中,我添加了:
var domainValidPublisher: AnyPublisher<Bool, Never> {
$domain
.debounce(for: 0.5, scheduler: DispatchQueue.main)
.removeDuplicates()
.map { domain in
URL.isValidURL(urlString: domain)
}
.eraseToAnyPublisher()
}
然后,我可以在init
中进行订阅。
我还在AnyCancellable
上添加了称为.cancel()
的{{1}}属性。
更新后的模型如下所示:
deinit