我正在学习Combine以及它如何使用发布者更新值。目前,我已经创建了一个变量,当验证失败时,它会更新自己。
var nameError: AnyPublisher<String, Never> {
$name
.dropFirst()
.debounce(for: 0.2, scheduler: RunLoop.main)
.removeDuplicates()
.map {
if $0.isEmpty || !self.isValidName() {
return "Name not valid"
}
return "Name"
}
.eraseToAnyPublisher()
}
我想把它附加到一个Text((标签上,这样它就会更新。在合并之前,我会有一个var error: String
,我会对照它进行检查。但现在我得到错误Cannot convert value of type 'AnyPublisher<String, Never>' to expected argument type 'String'
如何转换var error: String
消息以接收AnyPublisher<字符串,从不>?
下面是一个游乐场,我认为它实现了您的要求。
结果是,您在onAppear
中订阅了发布者,并将订阅保持在视图的状态。发布新值时,将更新包含标题的状态。
import UIKit
import SwiftUI
import Combine
import PlaygroundSupport
class ModelObject : ObservableObject {
@Published var name: String = ""
var nameError: AnyPublisher<String, Never> {
$name
.dropFirst()
.debounce(for: 0.2, scheduler: RunLoop.main)
.print()
.removeDuplicates()
.map {
if $0.isEmpty || !self.isValidName() {
return "Name not valid"
}
return ""
}
.eraseToAnyPublisher()
}
func isValidName() -> Bool {
return name.caseInsensitiveCompare("Scott") != .orderedSame
}
}
struct TextControl : View {
@StateObject var viewModel = ModelObject()
@State var caption : String = ""
@State var subscription : AnyCancellable?
var body : some View {
VStack(alignment: .leading) {
TextField("Entry", text: $viewModel.name)
Text(caption)
.font(.caption)
.foregroundColor(.red)
}
.padding()
.frame(width: 320, height: 240)
.onAppear {
self.subscription = viewModel.nameError.sink { self.caption = $0}
}
}
}
let viewController = UIHostingController(rootView: TextControl())
PlaygroundSupport.PlaygroundPage.current.liveView = viewController