I have introduced a styled NSViewRepresentable text field on to my layout in order to use an attributed Text Editor field. I want to influence the content of this text field through some buttons.
I can change the styled attributes of the field, but it never refreshes unless I hit it manually. There must be a way of getting to do this automatically. What have I missed?
import SwiftUI
import Combine
let publisher = PassthroughSubject<Bool,Never>()
struct ContentView: View
{
    @State var mytext = NSMutableAttributedString(string: "")
    var attributedString: NSMutableAttributedString
    @State var textViewID: Int = 0
    
    init()
    {
        attributedString = NSMutableAttributedString(
            string: "Hello World!",
            attributes: [.font: NSFont.systemFont(ofSize: 18)])
        _mytext = State(initialValue: attributedString)
    }
    
    var body: some View
    {
        VStack
        {
            Button("Bold")
            {
                attributedString.addAttribute(.font, value: NSFont.boldSystemFont(ofSize: 18), range: NSRange(location: 0, length: 5))
                mytext = attributedString
                publisher.send(true)
            }
        }
        TextView(text: $mytext)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .id(textViewID)
            .onReceive(publisher) { ( stateTo ) in
                textViewID += 1
            }
    }
}
struct TextView: NSViewRepresentable
{
    @Binding var text: NSMutableAttributedString
    
    func makeNSView(context: Context) -> NSTextView 
    {
        NSTextView()
    }
    
    func updateNSView(_ nsView: NSTextView, context: Context)
    {
        nsView.textStorage?.setAttributedString(text)
    }
}
Or am I missing something and there is a much easier way?
 
                        
Suspect worked around this and moved onto bigger fish. But for the benefit of those bumping into something similar :-)
The problem with the code in the example is that there is nothing in it that SwiftUI can use to determine when it needs to redraw.
Specifically
@State var mytext: NSMutableAttributedStringis holding a reference to the same attributed string asattributedStringdoes. Consequently the button actionmytext = attributedStringis from pov of SwiftUI a noop.Two approaches to making it work.
First as now, where the same string is kept and mutated in place and a redraw is in effect explicity requested. In this case the Button action can be cleaned up to remove the need for Combine and the
onReceivethus:Or second, get rid of the need for Combine, onReceive and id attribute by removing the mutation in place. Instead replace with a new attribute string that SwiftUI will notice, e.g.:
Later is probably slightly more idiomatic SwiftUI.