访问 StateObject 的对象而不将其安装在 View 上

问题描述 投票:0回答:1

关于这个问题还有其他答案,但没有看到可以解决问题,因为在我的例子中,我使用的是

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.
cocoa swiftui macos-sonoma nsviewrepresentable
1个回答
0
投票

我的猜测是这个错误:

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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.