How to link multiple text views to a single text storage in TextKit 2

In TextKit 1 we have the method NSTextStorage.addLayoutManager(_:) that allows to show the same text in multiple text views. This method exists with NSLayoutManager but not with NsTextLayoutManager.

Is there a way to achieve the same thing with TextKit 2?

Answered by DTS Engineer in 793290022

I believe the following sample code has what you are looking for:

Specifically, please see toggleHidden() in TextAttachment.swift for how to change the text storage programmatically.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Content manager allows to addition one or more layout managers.

let layoutManager = NSTextLayoutManager()
layoutManager.textContainer = textContainer

let contentManager = NSTextContentStorage()
contentManager.addTextLayoutManager(layoutManager)

that you can later assess via contentManager.textLayoutManagers. Additionally there is a flag automaticallySynchronizesTextLayoutManagers (defaults to true) to facilitate synchronization of multiple layout managers for that content manager.

Thanks! I have another question now: how can I link multiple NSTextContentStorage to the same NSTextStorage? The documentation for NSTextContentStorage reads:

By default, the framework initializes the NSTextContentStorage with NSTextStorage as the backing store.

But I don't see any way of accessing or setting the NSTextStorage. If I'm not supposed to do so, then how can I programmatically change the text?

I believe the following sample code has what you are looking for:

Specifically, please see toggleHidden() in TextAttachment.swift for how to change the text storage programmatically.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Thanks. The part I was missing is the one the documentation for NSTextContentManager doesn't mention, which is that it is an abstract class whose (apparently) only concrete subclass is NSTextContentStorage, which has a textStorage property.

guard let textStorage: NSTextStorage = (textLayoutManager?.textContentManager as? NSTextContentStorage)?.textStorage else { return }

The sample code also changes the textStorage inside the block passed to textContentManager.performEditingTransaction(_:), which the documentation doesn't seem to explain why it's necessary.

I've found the documentation on this topic to be really awful with little to explain the relationships between all these elements and the existing documentation to be outdated using TextKit1

(Note the below is archived) https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TextSystemArchitecture/ArchitectureOverview.html

@DTS Engineer is there any docs for TextKit2 and how its new classes interface with each other?

The TextKit2 sample code has a lot of nuance which is impossible to learn unless you know it exists

The sample code also changes the textStorage inside the block passed to textContentManager.performEditingTransaction(_:), which the documentation doesn't seem to explain why it's necessary.

If I remember correctly, we mentioned that in the Meet TextKit 2 WWDC session when doing the code demo, but it is unfortunate that we haven't documented that in the API reference. You might consider filing a feedback report (http://developer.apple.com/bug-reporting/) against that.

Making changes on textStorage in the closure of performEditingTransaction(_:) is important because it makes sure the changes are synchronized to the text layout managers and trigger a text view update, if necessary. Please be sure that you do that whenever you change the text storage.

is there any docs for TextKit2 and how its new classes interface with each other?

To understand how the classes interact with each other, the best thing to get started is probably the Meet TextKit 2 WWDC session, as mentioned above.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

How to link multiple text views to a single text storage in TextKit 2
 
 
Q