0

我曾尝试使用 Coordinator 类创建一个 TextView 但这似乎总是保留与原始对象的绑定。

如果我在这样的 SwiftUI 视图中使用它,那么如果我在主/详细信息排列中使用 DocView 并传入一个新的 Doc 对象,那么 TextView 将始终保持与第一个文档的绑定。

因此,如果有文档或项目列表,则选择第二个或第三个文档并为该文档创建DOCVIEW时,对文本视图的任何编辑都将更新第一个文档详细信息。

因此,似乎协调器或其他东西保留了原始绑定,而不是更新以反映 DocView 变量 doc 的最新实例。

我是否误解了 Coordinator 应该如何工作,如果是这样,我如何确保在创建新的 DocView(doc: newdocobject) 时更新绑定。

实际上,TextView 将显示 newdocobject 详细信息,但任何时候进行任何编辑,目标似乎仍然是原始对象

编辑:示例应用程序https://duncangroenewald.com/files/SampleApps/TextView.zip

问题的更好说明 https://duncangroenewald.com/files/SampleApps/TextView2.zip

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:"New doc details")
   }

}


    //
    //  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) -> OSTextView {
            let textView = OSTextView()
            textView.delegate = context.coordinator
     
            return textView
        }
     
        func updateUIView(_ uiView: OSTextView, context: Context) {
            uiView.attributedText = attributedText
        }
        
        func makeCoordinator() -> Coordinator {
            Coordinator($attributedText)
        }
         
        class Coordinator: NSObject, UITextViewDelegate {
            var text: Binding<NSAttributedString>
         
            init(_ text: Binding<NSAttributedString>) {
                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) -> OSTextView {
            let textView = OSTextView(frame: .zero)
            textView.delegate = context.coordinator
            return textView
        }
     
        func updateNSView(_ nsView: OSTextView, context: Context) {
            nsView.textStorage?.setAttributedString(attributedText)
        }
        
        func makeCoordinator() -> Coordinator {
            return Coordinator($attributedText)
        }
         
        class Coordinator: NSObject, NSTextViewDelegate {
            var text: Binding<NSAttributedString>
         
            init(_ text: Binding<NSAttributedString>) {
                self.text = text
                super.init()
            }
         
            func textDidChange(_ notification: Notification) {
                if let textView = notification.object as? NSTextView {
                    self.text.wrappedValue = textView.attributedString()
                }
            }
        }
    }
    
    #endif

编辑:我认为 Apples 实现 NSAttributedString 绑定可能存在错误。

通过执行以下操作,我似乎已经克服了这个问题。

TextView(attributedText: Binding(get: {doc.details}, set: {doc.details = NSAttributedString(attributedString: $0)}))

没有比这更糟糕的了——SwiftUI 似乎对它的绑定完全感到困惑,并保留了对前一个对象的引用。

我的解决方法是在全局变量(单例)中保留对视图中显示的选定对象的引用,并对单例中保存的对象执行 get{} set{}。

这现在似乎工作只是找到。我已经向 Apple 记录了错误报告。不确定这是否与 NSAttributedString 或是否与 NSViewRepresentable 有关。

所以绑定现在看起来像这样

          TextView(attributedText: Binding(get: {

                return get()
                
            }, set: {

                set($0)
            }))
        

而这两种方法是这样的。请注意,我仍然必须复制属性字符串!

func get()->NSAttributedString {

if let no = fileList.selectedNode {


    return no.wrappedDetails
    
} else {
    return NSAttributedString(string: "")
}

} func set(_ attribString: NSAttributedString) {

if let no = fileList.selectedNode {


no.wrappedDetails = NSAttributedString(attributedString: attribString)
    
}

}

4

0 回答 0