title: How can I create a SwiftUI TextView that will update the binding when a new view gets created
body: <p>I have tried using the Coordinator class to create a TextView but this seems to always retain the binding to the original object.</p>
  <p>If I use this in a SwiftUI view like this then if I use the DocView in a master/detail arrangement and pass in a new Doc object then the TextView will always hold the binding to the first document.</p>
  <p>So if there is a list of docs or items then when a second or third doc is selected and the DocView is created for that Doc then any edits to the TextView will update the first documents details.</p>
  <p>So it seems the Coordinator or something is retaining the original binding rather than updating to reflect the latest instance of DocView variable doc.</p>
  <p>Have I misunderstood how Coordinator is supposed to work, and if so how can I make sure that when a new DocView(doc: newdocobject) is created that the binding will be updated.</p>
  <p>In practice the TextView will display the newdocobject details but any time any edit is made the target seems to still be the original object</p>
  <p>EDIT: Sample app <a href="https://duncangroenewald.com/files/SampleApps/TextView.zip" rel="nofollow noreferrer">https://duncangroenewald.com/files/SampleApps/TextView.zip</a></p>
  <p>A better illustration of the problem
  <a href="https://duncangroenewald.com/files/SampleApps/TextView2.zip" rel="nofollow noreferrer">https://duncangroenewald.com/files/SampleApps/TextView2.zip</a></p>
  <pre><code>struct DocView: View {
     @ObservedObject var doc: Doc
  
     var body: some View {
  
        TextView(attributedText: $doc.details)
  
     }
  }
  
  class Doc: NSObject, ObservableObject {
     var name: String
     
     var details: NSAttributedString
  
     init(name: String) {
        self.name = name
        self.details = NSAttributedString(string:&quot;New doc details&quot;)
     }
  
  }
  
  
      //
      //  TextView.swift
      //  DocApp
      //
      //  Created by Duncan Groenewald on 11/12/21.
      //  Copyright © 2021 Apple. All rights reserved.
      //
      
      import Foundation
      import SwiftUI
      
      #if !os(macOS)
       
      struct TextView: UIViewRepresentable {
       
          @Binding var attributedText: NSAttributedString
          
          func makeUIView(context: Context) -&gt; OSTextView {
              let textView = OSTextView()
              textView.delegate = context.coordinator
       
              return textView
          }
       
          func updateUIView(_ uiView: OSTextView, context: Context) {
              uiView.attributedText = attributedText
          }
          
          func makeCoordinator() -&gt; Coordinator {
              Coordinator($attributedText)
          }
           
          class Coordinator: NSObject, UITextViewDelegate {
              var text: Binding&lt;NSAttributedString&gt;
           
              init(_ text: Binding&lt;NSAttributedString&gt;) {
                  self.text = text
              }
           
              func textViewDidChange(_ textView: UITextView) {
                  self.text.wrappedValue = textView.attributedText
              }
          }
      }
      
      #endif
      
      #if os(macOS)
       
      struct TextView: NSViewRepresentable {
       
          @Binding var attributedText: NSAttributedString
          
          func makeNSView(context: Context) -&gt; OSTextView {
              let textView = OSTextView(frame: .zero)
              textView.delegate = context.coordinator
              return textView
          }
       
          func updateNSView(_ nsView: OSTextView, context: Context) {
              nsView.textStorage?.setAttributedString(attributedText)
          }
          
          func makeCoordinator() -&gt; Coordinator {
              return Coordinator($attributedText)
          }
           
          class Coordinator: NSObject, NSTextViewDelegate {
              var text: Binding&lt;NSAttributedString&gt;
           
              init(_ text: Binding&lt;NSAttributedString&gt;) {
                  self.text = text
                  super.init()
              }
           
              func textDidChange(_ notification: Notification) {
                  if let textView = notification.object as? NSTextView {
                      self.text.wrappedValue = textView.attributedString()
                  }
              }
          }
      }
      
      #endif
  </code></pre>
  <p>EDIT:
  I think maybe there is a bug with Apples implementation for NSAttributedString bindings.</p>
  <p>By doing the following I seem to have overcome the issue.</p>
  <pre><code>TextView(attributedText: Binding(get: {doc.details}, set: {doc.details = NSAttributedString(attributedString: $0)}))
  </code></pre>
  <p>No its worse that this - it seems SwiftUI gets completely confused about its bindings and retains references to the previous object.</p>
  <p>My workaround is to keep a reference in a global variable (singleton) to the selected object being displayed in the View and to perform the get{} set{} on the object held in the singleton.</p>
  <p>This now seems to work just find.  I have logged a bug report with Apple. Not sure if this is related to NSAttributedString or whether it is to do with NSViewRepresentable.</p>
  <p>So the binding now looks like this</p>
  <pre><code>          TextView(attributedText: Binding(get: {
  
                  return get()
                  
              }, set: {
  
                  set($0)
              }))
          
  </code></pre>
  <p>And the two methods are like this.  Note that I still have to copy the attributed string !</p>
  <p>func get()-&gt;NSAttributedString {</p>
  <pre><code>if let no = fileList.selectedNode {
  
  
      return no.wrappedDetails
      
  } else {
      return NSAttributedString(string: &quot;&quot;)
  }
  </code></pre>
  <p>}
  func set(_ attribString: NSAttributedString) {</p>
  <pre><code>if let no = fileList.selectedNode {
  
  
  no.wrappedDetails = NSAttributedString(attributedString: attribString)
      
  }
  </code></pre>
  <p>}</p>