如何使 Swift 协调器反映 parent 的绑定更改?

How to make Swift Coordinator reflect parent's bindings changes?

假设我有:

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 副本,即使 parent 发生变化(@Binding doc 已更新),它仍然引用旧副本?

如何让 Coordinator 反映 parent 的绑定变化?

谢谢!

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
        }
    }
    // ...

Is it true, that Coordiantor keeps it's own copy of parent, and even if parent changes (@Binding doc is updated), it still references to old one?

一个parent,即这里的EditorView,是struct,所以答案是肯定的,一般是可以复制的。

How to make Coordinator reflect parent's bindings changes?

而不是(或附加于)父级,将绑定显式注入协调器(通过构造函数)并直接使用它。