I’m embedding an NSTextView (TextKit 2) inside a SwiftUI app using NSViewRepresentable. I’m trying to highlight dynamic subranges (changing as the user types) by providing per-range rendering attributes via NSTextLayoutManager’s rendering-attributes mechanism.
The issue: the highlight is unreliable.
-
Often, the highlight doesn’t appear at all even though the delegate/data source is returning attributes for the expected range.
-
Sometimes it appears once, but then it stops updating even when the underlying “highlight range” changes.
This feels related to SwiftUI - AppKit layout issue when using NSViewRepresentable (as said in https://developer.apple.com/documentation/swiftui/nsviewrepresentable).
What I’ve tried
-
Updating the state that drives the highlight range and invalidating layout fragments / asking for relayout
-
Ensuring all updates happen on the main thread.
-
Calling setNeedsDisplay(_:) on the NSViewRepresentable’s underlying view.
-
Toggling the SwiftUI view identity (e.g. .id(...)) to force reconstruction (works, but too expensive / loses state).
Question
In a SwiftUI + NSViewRepresentable setup with TextKit 2, what is the correct way to make NSTextLayoutManager re-query and redraw rendering attributes when my highlight ranges change?
-
Is there a recommended invalidation call for TextKit 2 to trigger re-rendering of rendering attributes?
-
Or is this a known limitation when hosting NSTextView inside SwiftUI, where rendering attributes aren’t reliably invalidated?
-
If this approach is fragile, is there a better pattern for dynamic highlights that avoids mutating the attributed string (to prevent layout/scroll jitter)?