关于这个问题还有其他答案,但没有看到可以解决问题,因为在我的例子中,我使用的是
NSViewRepresentable
cocoa 视图,这不完全是 SwiftUI 视图。
我有这个代码:
struct MyObject: Hashable, Identifiable {
let id: UUID = UUID()
var name, brand: String
init(name: String = "", brand: String = "") {
self.name = varName
self.brand = brand
}
}
final class Model:ObservableObject {
@Published var objects = (0..<3).compactMap {_ in
return MyObject()
}
}
struct ContentView: View {
private let columns = [GridItem(.flexible()), GridItem(.flexible())]
@StateObject private var model = Model()
var body: some View {
VStack{
LazyVGrid(
columns: columns,
alignment: .center,
spacing: 10,
pinnedViews: []
) {
ForEach($model.objects, id:\.id) {$object in
MyTextField($initObject)
}
}
}
.padding(20)
}
}
struct MyTextField: View {
@Binding private var initObject:InitObject
init(_ initObject:Binding<InitObject>) {
_initObject = initObject
}
var body: some View {
AppKitTextField(property: $initObject.name,
placeholder: "name",
fontName:"Avenir-Medium",
fontSize:18) { text in
}
MyAppKitTextField(property: $initObject.type,
placeholder: "type",
fontName:"Avenir-Medium",
fontSize:18)
}
}
问题是
MyAppKitTextField
是一个AppKit NSTextField
NSViewRepresentable
,就像这样:
public struct AppKitTextField: NSViewRepresentable {
public typealias NSViewType = NSTextField
@Binding var property: String
public init(property: Binding<String>) {
self._property = property
}
public class Coordinator: NSObject, NSTextFieldDelegate {
@Binding private var text: String
init(text: Binding<String>) {
self._text = text
}
}
public func makeNSView(context: NSViewRepresentableContext<AppKitTextField>) -> NSTextField {
let textField = NSTextField()
textField.delegate = context.coordinator
textField.stringValue = property
return textField
}
public func makeCoordinator() -> AppKitTextField.Coordinator {
return Coordinator(text: $property)
}
public func updateNSView(_ nsView: NSTextField, context: Context) {
nsView.stringValue = property
}
}
}
我的问题是线路
@Binding var property: String
当我尝试使用此视图时,我看到此错误:
Accessing StateObject's object without being installed on a View. This will create a new instance each time.
我的猜测是这个错误:
public func makeCoordinator() -> AppKitTextField.Coordinator {
return Coordinator(text: $property)
}
应该是:
public func makeCoordinator() -> AppKitTextField.Coordinator {
return Coordinator() // make is only called once so there is no point in giving it an old version of the binding.
}
public func updateNSView(_ nsView: NSTextField, context: Context) {
context.coordinator.textDidChange = nil // just to prevent endless updates depending on how your coordinator is designed
nsView.stringValue = property
// use the new version of the binding
context.coordinator.textDidChange = { text
self.property = text
}
}