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

如何在NSViewRepresentable中监听@Observable类的变更

监听AnnotationsCoordinator变更的几种实现方案

方案1:利用SwiftUI的updateNSView自动触发更新

因为@Observable类的属性变更会触发SwiftUI视图重计算,进而自动调用updateNSView方法。你只需要在这个方法里把最新的注释数据传递给MyTextView并触发重绘即可:

func updateNSView(_ view: NSView, context: Context) {
    if let textView = context.coordinator.textView as? MyTextView {
        // 同步最新的注释数组
        textView.annotations = annotationsCoordinator.annotations
        // 触发视图重绘
        textView.setNeedsDisplay(textView.bounds)
    }
}

这个方案最简洁,不需要额外的监听逻辑,依赖SwiftUI自身的状态更新机制即可完成同步。

方案2:在自定义Coordinator中订阅属性变更

如果需要更精细的控制(比如只监听annotations的变化,而非整个对象的任意变更),可以在MyViewCoordinator中使用ObservationTracker来订阅目标属性:

修改MyViewCoordinator的实现:

class MyViewCoordinator {
    let parent: MyCustomTextView
    let annotationsCoordinator: AnnotationsCoordinator
    private var observationToken: ObservationToken?

    init(_ parent: MyCustomTextView, _ annotationsCoordinator: AnnotationsCoordinator) {
        self.parent = parent
        self.annotationsCoordinator = annotationsCoordinator
        
        // 订阅annotations属性的变更
        observationToken = withObservationTracking {
            // 必须显式访问要监听的属性,否则无法触发回调
            _ = self.annotationsCoordinator.annotations
        } onChange: { [weak self] in
            guard let self = self, let textView = self.parent.context?.coordinator.textView as? MyTextView else { return }
            textView.annotations = self.annotationsCoordinator.annotations
            textView.setNeedsDisplay(textView.bounds)
        }
    }
}

注意用weak self避免循环引用,同时确保MyViewCoordinator持有annotationsCoordinator的强引用。

方案3:让MyTextView直接监听变更

如果MyTextView需要独立响应注释变化,可以让它直接持有AnnotationsCoordinator的引用并订阅变更:

class MyTextView: NSTextView {
    var annotations: [Annotation] = []
    private var observationToken: ObservationToken?
    
    func bindAnnotationsCoordinator(_ coordinator: AnnotationsCoordinator) {
        observationToken = withObservationTracking {
            _ = coordinator.annotations
        } onChange: { [weak self] in
            guard let self = self else { return }
            self.annotations = coordinator.annotations
            self.setNeedsDisplay(self.bounds)
        }
    }
}

然后在makeNSView方法中完成绑定:

func makeNSView(context: Context) -> NSView {
    let textView = MyTextView()
    textView.bindAnnotationsCoordinator(annotationsCoordinator)
    context.coordinator.textView = textView
    return textView
}

关键注意事项

  • 父视图中必须用@State持有AnnotationsCoordinator实例,这样SwiftUI才能捕获到它的属性变更。
  • 使用withObservationTracking时,必须在闭包内显式访问要监听的属性(比如coordinator.annotations),否则无法触发变更回调。
  • UI更新操作默认在主线程执行,无需额外处理。

内容的提问来源于stack exchange,提问作者koen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:35:59