You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

选区变化时通过NSViewRepresentable传递NSTextView值至SwiftUI父视图

Great question! You don’t need to create a custom delegate or new notification—you can actually get the NSTextView instance directly from the notification object passed to textViewDidChangeSelection. Here’s how to modify your coordinator to access the text view and update your bindings:

Updated Coordinator Implementation

class Coordinator: NSObject, NSTextViewDelegate {
    var parent: TextViewMacOS
    
    init(_ parent: TextViewMacOS) {
        self.parent = parent
    }
    
    func textViewDidChangeSelection(_ notification: Notification) {
        // Retrieve the text view from the notification object
        guard let textView = notification.object as? NSTextView else { return }
        
        // Update typing attributes binding
        let newTypingAttributes = textView.typingAttributes
        // Optional: Check for changes to avoid redundant SwiftUI re-renders
        if parent.currentTypingAttributes != newTypingAttributes {
            DispatchQueue.main.async {
                self.parent.currentTypingAttributes = newTypingAttributes
            }
        }
        
        // Get attributes at the current selection position
        let selectedRange = textView.selectedRange()
        guard let textStorage = textView.textStorage else {
            // Fallback to typing attributes if textStorage is unavailable
            DispatchQueue.main.async {
                self.parent.currentTextAttributes = newTypingAttributes
            }
            return
        }
        
        // Handle edge case where selection is at the end of the text
        let attributePosition = min(selectedRange.lowerBound, textStorage.length - 1)
        
        var effectiveRange = NSRange()
        let newTextAttributes = textStorage.attributes(at: attributePosition, effectiveRange: &effectiveRange)
        
        // Optional: Check for changes before updating binding
        if parent.currentTextAttributes != newTextAttributes {
            DispatchQueue.main.async {
                self.parent.currentTextAttributes = newTextAttributes
            }
        }
    }
}

Key Details Explained

  • Retrieve the text view: The notification’s object property is the NSTextView that triggered the selection change, so we safely cast it to access its properties.
  • Main thread safety: We wrap binding updates in DispatchQueue.main.async to ensure UI-related changes happen on the main thread (critical for SwiftUI state updates).
  • Edge case handling:
    • If textStorage is nil, we fall back to using the current typing attributes.
    • If the selection is at the very end of the text, we adjust the position to the last character to get valid attributes.
  • Redundant update prevention: Comparing the new attributes to the current binding value helps avoid unnecessary SwiftUI re-renders. Note that comparing dictionaries with Any values can be limited—if you need precise equality checks, consider comparing specific attributes (like .font, .foregroundColor) instead of the entire dictionary.

Don’t Forget to Set the Delegate

Make sure you assign the coordinator as the text view’s delegate in your makeNSView method:

public func makeNSView(context: Context) -> NSTextView {
    let textView = NSTextView()
    textView.delegate = context.coordinator
    // Add your other text view setup here (e.g., text storage, layout manager)
    return textView
}

内容的提问来源于stack exchange,提问作者santi.gs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:53:26