与 "RichTextField" 绑定(即 NSViewRepresentable 中的 NSTextView)- 值在重绘、LostFocus 等后重置

Binding with "RichTextField" (i.e. NSTextView in NSViewRepresentable) - Value resets after redraw, LostFocus, etc

我正在努力使用定制的 RichTextField,即 NSViewRepresentable 中的 NSTextView,它具有以下代码(在 的帮助下编程):

在代码中设置 attributedString 有效,我可以更改格式,但是一旦应用程序失去焦点,RichTextField 就会重置为以编程方式设置的最后一个值:

此外,在列表中使用 RichTextField 时,应用程序会进入循环。

RichTextField

import Foundation
import SwiftUI

struct RichTextField: NSViewRepresentable {
    typealias NSViewType = NSTextView
    
    @Binding var attributedString: NSMutableAttributedString 
    var isEditable: Bool
    
    func makeNSView(context: Context) -> NSTextView {
        let textView = NSTextView(frame: .zero)

        textView.textStorage?.setAttributedString(self.attributedString)
        textView.isEditable = isEditable

        textView.translatesAutoresizingMaskIntoConstraints = false 
        textView.autoresizingMask = [.width, .height] 

        return textView
    }

    func updateNSView(_ nsView: NSTextView, context: Context) {
        nsView.textStorage?.setAttributedString(self.attributedString)
    }

}

查看

import SwiftUI

struct EditWindow: View {
    
    @ObservedObject var model: EditEntryViewModel
    
 var body: some View {

        VStack (alignment: .leading, spacing: 20) {
            
            RichTextField(attributedString: self.$model.answer1, isEditable: true)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            Spacer()
            
        }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
        
    }
    
}

ViewModel

import Foundation
import SwiftUI

class EditEntryViewModel: ObservableObject {
    
    init(entryID: Int32) {
        
        let entryToUse = db.getEntry(id: entryID)
        
        id = entryToUse!.id
        answer1 = entryToUse!.answer1.getNSMutableAttributedStringFromHTML() // Converts HTML from the DB to a NSMutableAttributedString
        
    }
    
    @Published var id: Int32
    @Published var answer1: NSMutableAttributedString = NSMutableAttributedString() {
        didSet {
            print("NEW answer1: " + answer1.string)
        }
    }
    
}

不知道有没有办法将attributedString绑定到ViewModel?

非常感谢您的帮助。

不确定这是否是正确的方法,但我得到了使用以下代码的绑定:

import Foundation
import SwiftUI


struct RichTextField: NSViewRepresentable {
    typealias NSViewType = NSTextView
    
    @Binding var attributedString: NSAttributedString  
    var isEditable: Bool
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeNSView(context: Context) -> NSTextView {
        let textView = NSTextView(frame: .zero)
        
        textView.textStorage?.setAttributedString(self.attributedString)
        textView.isEditable = isEditable
        textView.delegate = context.coordinator
        
        textView.translatesAutoresizingMaskIntoConstraints = false 
        textView.autoresizingMask = [.width, .height] 

        return textView
    }

    func updateNSView(_ nsView: NSTextView, context: Context) {
        nsView.textStorage!.setAttributedString(self.attributedString)
    }

    // Source: https://medium.com/fantageek/use-xib-de9d8a295757
    class Coordinator: NSObject, NSTextViewDelegate {
        let parent: RichTextField
        
        init(_ RichTextField: RichTextField) {
            self.parent = RichTextField
        }

        func textDidChange(_ notification: Notification) {

            guard let textView = notification.object as? NSTextView else { return }
            self.parent.attributedString = textView.attributedString()

        }

    }
    
}

(尽管在列表(不可编辑)中使用 RichTextField 时我仍然收到“检测到循环”错误。)