The vast majority of applications interact with the text system at a high level through one class: NSTextView. It is also possible to build the network of objects that make up the text system from the bottom up, starting with the NSTextStorage object. Understanding how this is done helps illuminate the design of the text-handling system.
In creating the text-handling network by hand, you create four objects but then release three as they are added to the network. You are left with a reference only to the NSTextStorage object. The NSTextView is retained, however, by both its NSTextContainer and its superview; to fully destroy this group of text objects you must send removeFromSuperview
to the NSTextView object and then release the NSTextStorage object.
An NSTextStorage object is conceptually the owner of any network of text objects, no matter how complex. When you release the NSTextStorage object, it releases its NSLayoutManagers, which release their NSTextContainers, which in turn release their NSTextViews.
However, recall that the text system implements a simplified ownership policy for those whose only interaction with the system is through the NSTextView class. See “Creating an NSTextView Programmatically” for more information.
Set Up an NSTextStorage Object
Set Up an NSLayoutManager Object
Set Up an NSTextContainer Object
Set Up an NSTextView Object
You create an NSTextStorage object in the normal way, using the alloc
and init...
messages. In the simplest case, where there’s no initial contents for the NSTextStorage, the initialization looks like this:
textStorage = [[NSTextStorage alloc] init]; |
If, on the other hand, you want to initialize an NSTextStorage object with rich text data from a file, the initialization looks like this (assume filename
is defined):
textStorage = [[NSTextStorage alloc] |
initWithRTF:[NSData dataWithContentsOfFile:filename] |
documentAttributes:NULL]; |
We’ve assumed that textStorage
is an instance variable of the object that contains this method. When you create the text-handling system by hand, you need to keep a reference only to the NSTextStorage object as you’ve done here. The other objects of the system are owned either directly or indirectly by this NSTextStorage object, as you’ll see in the next steps.
Next, create an NSLayoutManager object:
NSLayoutManager *layoutManager; |
layoutManager = [[NSLayoutManager alloc] init]; |
[textStorage addLayoutManager:layoutManager]; |
[layoutManager release]; |
Note that layoutManager
is released after being added to textStorage
. This is because the NSTextStorage object retains each NSLayoutManager that’s added to it—that is, the NSTextStorage object owns its NSLayoutManagers.
The NSLayoutManager needs a number of supporting objects—such as those that help it generate glyphs or position text within a text container—for its operation. It automatically creates these objects (or connects to existing ones) upon initialization. You only need to connect the NSLayoutManager to the NSTextStorage object and to the NSTextContainer object, as seen in the next step.
Next, create an NSTextContainer and initialize it with a size. Assume that theWindow
is defined and represents the window that displays the text view.
NSRect cFrame = [[theWindow contentView] frame]; |
NSTextContainer *container; |
container = [[NSTextContainer alloc] |
initWithContainerSize:cFrame.size]; |
[layoutManager addTextContainer:container]; |
[container release]; |
Once you’ve created the NSTextContainer, you add it to the list of containers that the NSLayoutManager owns, and then you release it. The NSLayoutManager now owns the NSTextContainer and is responsible for releasing it when it’s no longer needed. If your application has multiple NSTextContainers, you can create them and add them at this time.
Finally, create the NSTextView (or NSTextViews) that displays the text:
NSTextView *textView = [[NSTextView alloc] |
initWithFrame:cFrame textContainer:container]; |
[theWindow setContentView:textView]; |
[theWindow makeKeyAndOrderFront:nil]; |
[textView release]; |
Note that initWithFrame:textContainer:
is used to initialize the NSTextView. This initialization method does nothing more than what it says: initialize the receiver and set its text container. This is in contrast to initWithFrame:
, which not only initializes the receiver, but creates and interconnects the network of objects that make up the text-handling system. Once the NSTextView has been initialized, it’s added to the window, which is then displayed. Finally, you release the NSTextView.
© 1997, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-04-08)