如何使Swift Coordinator反映父母的绑定变化?

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

假设我有:

  • 结构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
    }

我想传递绑定引用有些混乱。

swift swiftui appkit combine
1个回答
1
投票

是的,Coordiantor保留自己的父母副本,甚至如果父项发生更改(@Binding doc已更新),它仍然引用旧的吗?

© www.soinside.com 2019 - 2024. All rights reserved.