假设我有:
Document
,代表文本文档。EditorView
—用合并到NSTextView
的Combine包裹的Document.content<String>
。 [Document
是复数store:ObservableObject
的一部分,因此可以将其绑定到EditorView
实例。
当我第一次创建绑定时,它可以按预期的方式工作-编辑NSTextView会更改Document.content
中的值。
let document1 = Document(...)
let document2 = Document(...)
var editor = EditorView(doc: document1)
但是如果更改绑定到另一个文档...
editor.doc = document2
...然后updateNSView
可以看到新的document2
。但是在Coordiantor的textDidChange
内部仍然引用document1
。
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.doc.content = textView.string
self.selectedRanges = textView.selectedRanges
}
因此,最初,当我设置新的bindint时,NSTextView将其内容更改为document2
,但是当我键入内容时,协调器会将更改发送到document1
。
是真的,Coordiantor保留了它自己的parent
副本,即使父项更改(@Binding doc
已更新),它仍然引用旧的副本?
如何使协调器反映父母的绑定更改?
谢谢!
struct Document: Identifiable, Equatable {
let id: UUID = UUID()
var name: String
var content: String
}
struct EditorView: NSViewRepresentable {
@Binding var doc: Document
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView(context: Context) -> CustomTextView {
let textView = CustomTextView(
text: doc.content,
isEditable: isEditable,
font: font
)
textView.delegate = context.coordinator
return textView
}
func updateNSView(_ view: CustomTextView, context: Context) {
view.text = doc.content
view.selectedRanges = context.coordinator.selectedRanges
}
}
// MARK: - Coordinator
extension EditorView {
class Coordinator: NSObject, NSTextViewDelegate {
var parent: EditorView
var selectedRanges: [NSValue] = []
init(_ parent: EditorView) {
self.parent = parent
}
func textDidBeginEditing(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.doc.content = textView.string
self.parent.onEditingChanged()
}
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.doc.content = textView.string
self.selectedRanges = textView.selectedRanges
}
func textDidEndEditing(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.doc.content = textView.string
self.parent.onCommit()
}
}
}
// MARK: - CustomTextView
final class CustomTextView: NSView {
private var isEditable: Bool
private var font: NSFont?
weak var delegate: NSTextViewDelegate?
var text: String {
didSet {
textView.string = text
}
}
// ...
试图直接将绑定传递给coordianator
// Passing binding to Coordinator
func makeCoordinator() -> Coordinator {
Coordinator(self, document: self.$doc)
}
在协调器中使用:
extension EditorView {
class Coordinator: NSObject, NSTextViewDelegate {
var document: Binding<Document>
var parent: EditorView
var selectedRanges: [NSValue] = []
init(_ parent: EditorView, document: Binding<Document>) {
self.parent = parent
self.document = document
}
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.document.content = textView.string // <= this gives error "Cannot assign to property: 'self' is immutable"
self.selectedRanges = textView.selectedRanges
}
我想传递绑定引用有些混乱。
是的,Coordiantor保留自己的父母副本,甚至如果父项发生更改(@Binding doc已更新),它仍然引用旧的吗?