我正在构建一个AutoCompletion视图,并希望传递一个包含要自动完成的字段的对象。 当前,我需要对一种属性进行自动完成的两种不同类型,两个属性的名称相同。我已经创建了一个协议,并正在使用它来构建通用视图以接受它。
我遇到的问题是onReceive破坏了编译。不幸的是,除了“无法推断复杂的闭包返回类型...”之外,我无法获得任何错误消息,但是如果我注释掉onReceive,则错误会清除。
如果我将结构中的LocationNameAutoComplete替换为Address,则它可以编译并正常运行-但这意味着我不能将其与其他类型的FactorySite一起使用。
如果我可以看到有关onReceive的实际错误消息,那将是一个开始...
有更好的方法吗?
谢谢
struct LocationNameTextField<T>: View where T: LocationNameAutoComplete {
@ObservedObject var address: T
var body: some View {
VStack {
TextField("", text: $address.location_name)
.onReceive(self.address.$location_name) { attr in
print("OK")
}
}
}
}
protocol LocationNameAutoComplete: ObservableObject {
var location_name: String {get set}
}
struct Address: LocationNameAutoComplete {
@Published var location_name: String
}
struct FactorySite: LocationNameAutoComplete {
@Published var location_name: String
}
答案 0 :(得分:2)
您在协议中的location_name
属性不是发布者,因此您不能在常规视图中引用它,唯一的发布者是objectWillChange
。
这是可编译的代码,包括一些其他修复程序(Xcode 11.7)
struct LocationNameTextField<T>: View where T: LocationNameAutoComplete {
@ObservedObject var address: T
var body: some View {
VStack {
TextField("", text: $address.location_name)
.onReceive(self.address.objectWillChange) { _ in
print("OK")
}
}
}
}
protocol LocationNameAutoComplete: ObservableObject {
var location_name: String {get set}
}
class Address: LocationNameAutoComplete {
@Published var location_name: String = ""
}
class FactorySite: LocationNameAutoComplete {
@Published var location_name: String = ""
}
更新:如果您需要某些属性的显式通用发布者(在这种情况下为location_name
),这是一种可行的方法
struct LocationNameTextField<T>: View where T: LocationNameAutoComplete {
@ObservedObject var address: T
var body: some View {
VStack {
TextField("", text: $address.location_name)
.onReceive(self.address.location_name_publisher) { attr in
print("OK")
}
}
}
}
protocol LocationNameAutoComplete: ObservableObject {
var location_name: String {get set}
var location_name_publisher: AnyPublisher<String, Never> { get }
}
class Address: LocationNameAutoComplete {
@Published var location_name: String = ""
var location_name_publisher: AnyPublisher<String, Never> {
$location_name.eraseToAnyPublisher()
}
}
class FactorySite: LocationNameAutoComplete {
@Published var location_name: String = ""
var location_name_publisher: AnyPublisher<String, Never> {
$location_name.eraseToAnyPublisher()
}
}
答案 1 :(得分:2)
错误是因为通用address.$location_name
不存在Published<String>
(您希望是T
的发布者),因为协议LocationNameAutoComplete
不存在要求它,并且您不能使用属性包装器@Published
自动合成此要求。
一种方法是手动定义发布者属性,并以每种符合类型的方式实现它(如Asperi所示)。
另一种方法是创建基类,而不是实现基类的协议:
class LocationNameAutoComplete: ObservableObject {
@Published var location_name: String
init(location: String) { self.location = location }
}
然后,几乎所有其他内容都保持不变:
struct LocationNameTextField<T>: View where T: LocationNameAutoComplete {
@ObservedObject var address: T
var body: some View {
VStack {
TextField("", text: $address.location_name)
.onReceive(self.address.$location_name) { attr in
print("OK")
}
}
}
}
class Address: LocationNameAutoComplete {}
class FactorySite: LocationNameAutoComplete {}