Developer Documentation
PATH  Mac OS X Documentation > Application Kit Reference: Objective-C

Table of Contents

NSAttributedString Class ClusterAdditions



Class Cluster Description


NSAttributedString objects manage character strings and associated sets of attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string. An association of characters and their attributes is called an attributed string. The cluster's two public classes, NSAttributedString and NSMutableAttributedString, declare the programmatic interface for read-only attributed strings and modifiable attributed strings, respectively. The Foundation Kit defines the basic functionality for attributed strings, while the remainder is defined here in the Application Kit. The Application Kit also uses a subclass of NSMutableAttributedString, called NSTextStorage, to provide the storage for the extended text-handling system.

NSAttributedString is not a subclass of NSString. It contains a string object to which it applies attributes. This protects users of attributed strings from ambiguities caused by the semantic differences between simple and attributed string. For example, equality can't be simply defined between an NSString and an attributed string.

Because of the nature of class clusters, attributed string objects are not actual instances of the NSAttributedString or NSMutableAttributedString classes, but are instances of one of their private concrete subclasses. Although an attributed string object's class is private, its interface is public, as declared by these abstract superclasses, NSAttributedString and NSMutableAttributedString. The attributed string classes adopt the NSCopying and NSMutableCopying protocols, making it convenient to convert an attributed string from one type to the other.

You create an NSAttributedString object from scratch by using one of initWithString:, initWithString:attributes:, or initWithAttributedString:. These methods initialize an attributed string with data you provide. You can also create an attributed string from RTF data using initWithRTF:documentAttributes:, initWithRTFD:documentAttributes:, initWithRTFDFileWrapper:documentAttributes:, or initWithPath:documentAttributes:.

An attributed string provides basic access to its contents with the string and attributesAtIndex:effectiveRange: methods, which yield characters and attributes, respectively. These two primitive methods are used by the other access methods to retrieve attributes individually by name, by functional group (font or ruler attributes, for example), and so on.


Feature Overview


NSAttributedString and NSMutableAttributedString add a number of features to the basic content storage of NSString:

An attributed string identifies attributes by name, storing their values as opaque ids in an NSDictionary. For example, the text font is stored as an NSFont object under the name given by NSFontAttributeName. You can associate any object value, by any name, with a given range of characters in the attributed string. The basic attributes defined by NSAttributedString are described in "Accessing Attributes" below.

A mutable attributed string keeps track of the attribute mapping as characters are added to and deleted from it and as attributes are changed. It allows you to group batches of edits with the beginEditing and endEditing methods, and to consolidate changes to the attribute-to-character mapping with the fix... methods.

An attributed string can be created from rich text (RTF) or rich text with attachments (RTFD), and can write its contents as RTF or RTFD data. Three initialization methods, initWithRTF:documentAttributes:, initWithRTFD:documentAttributes:, and initWithRTFDFileWrapper:documentAttributes:, interpret rich text data. The methods for writing rich text are RTFFromRange:documentAttributes: and RTFDFromRange:documentAttributes:, which return rich text data for any legal range within the attributed string, and RTFDFileWrapperFromRange:documentAttributes:, which returns the attributed string as an NSFileWrapper. NSAttributedString provides limited support for some document-level attributes. Additional support for rich text is provided by other text-handling classes such as NSTextView.

You can draw an attributed string in a focused NSView by invoking either the drawAtPoint: or drawInRect: method. Note that the Application Kit defines drawing methods for NSString as well, allowing any string object to draw itself. These methods, drawAtPoint:withAttributes: and drawInRect:withAttributes:, are described in the NSString Additions class specification.

An attributed string supports the typical behavior of editors in selecting a word on a double-click with the doubleClickAtIndex: method, and finds word breaks with nextWordFromIndex:forward:. It also calculates line breaks with the lineBreakBeforeIndex:withinRange: method


Accessing Attributes


An attributed string identifies attributes by name, storing an id value under the attribute name in an NSDictionary, which is in turn associated with an NSRange that indicates the characters to which the dictionary's attributes apply. You can assign any attribute name/value pair you wish to a range of characters, in addition to these standard attributes:


Attribute IdentifierValue ClassDefault Value
NSFontAttributeNameNSFontHelvetica 12-point
NSForegroundColorAttributeNameNSColorblack
NSBackgroundColorAttributeNameNSColornone (no background drawn)
NSUnderlineStyleAttributeNameNSNumber, as an intnone (no underline)
NSSuperscriptAttributeNameNSNumber, as an int0
NSBaselineOffsetAttributeNameNSNumber, as a float0.0
NSKernAttributeNameNSNumber, as a float0.0
NSLigatureAttributeNameNSNumber, as an int1 (standard ligatures)
NSParagraphStyleAttributeNameNSParagraphStyle(as returned by NSParagraphStyle's defaultParagraphStyle method)
NSAttachmentAttributeNameNSTextAttachmentnone (no attachment)

The identifiers listed are actually global NSString variables containing the attribute names. The value class is what users of an attributed string should expect the attribute values to be presented as. The default values are what they should assume if no attribute value has been explicitly set for the requested character range.

The natures of several attributes aren't obvious from name alone:

With an immutable attributed string, you assign all attributes on creating the string using methods such as initWithRTF:documentAttributes:, which interprets attributes from the RTF data, initWithRTF:documentAttributes:, which explicitly takes an NSDictionary of name/value pairs, or initWithString:, which assigns no attributes.

To retrieve attribute values from either type of attributed string, use any of these methods:

The first two methods return all attributes at a given index, the attribute:... methods return the value of a single named attribute, and fontAttributesInRange: and rulerAttributesInRange: return attributes defined to apply only to characters or to whole paragraphs, respectively (see the individual method descriptions for more information).

The first four methods also return by reference the effective range and the longest effective range of the attributes. These ranges allow you to determine the extent of attributes. Conceptually, each character in an attributed string has its own collection of attributes; however, it's often useful to know when the attributes and values are the same over a series of characters. This allows a routine to progress through an attributed string in chunks larger than a single character. In retrieving the effective range, an attributed string simply looks up information in its attribute mapping, essentially the dictionary of attributes that apply at the index requested. In retrieving the longest effective range, the attributed string continues checking characters past this basic range as long as the attribute values are the same. This extra comparison increases the execution time for these methods but guarantees a precise maximal range for the attributes requested. The code fragment below progresses through an attributed string in chunks based on the effective range. The fictitious analyzer object here counts the number of characters in each font. The while loop progresses as long as the effective range retrieved doesn't include the end of the attributed string, retrieving the font in effect just past the latest retrieved range. For each font attribute retrieved, analyzer is asked to tally the number of characters in the effective range. In this example, it's possible that consecutive invocations of attribute:atIndex:effectiveRange: will return the same value.

NSAttributedString *attrStr;
unsigned int length;
NSRange effectiveRange;
id attributeValue;

length = [attrStr length];
effectiveRange = NSMakeRange(0, 0);

while (NSMaxRange(effectiveRange) < length) {
    attributeValue = [attrStr attribute:NSFontAttributeName
        atIndex:NSMaxRange(effectiveRange) effectiveRange:&effectiveRange];
    [analyzer tallyCharacterRange:effectiveRange font:attributeValue];
}

In contrast, the next code fragment progresses through the attributed string according to the maximum effective range for each font. In this case, analyzer counts font changes, which may not be represented by merely retrieving effective ranges. In this case the while loop is predicated on the length of the limiting range, which begins as the entire length of the attributed string and is whittled down as the loop progresses. After analyzer records the font change, the limit range is adjusted to account for the longest effective range retrieved.

NSAttributedString *attrStr;
NSRange limitRange;
NSRange effectiveRange;
id attributeValue;

limitRange = NSMakeRange(0, [attrStr length]);

while (limitRange.length > 0) {
    attributeValue = [attrStr attribute:NSFontAttributeName
        atIndex:limitRange.location longestEffectiveRange:&effectiveRange
        inRange:limitRange];
    [analyzer recordFontChange:attributeValue];
    limitRange = NSMakeRange(NSMaxRange(effectiveRange),
        NSMaxRange(limitRange) - NSMaxRange(effectiveRange));
}

Note that the second code fragment is more complex. Because of this, and because attribute:atIndex:longestEffectiveRange:inRange: is somewhat slower than attribute:atIndex:effectiveRange:, you should typically use it only when absolutely necessary for the work you're performing. In most cases working by effective range is enough.


Changing a Mutable Attributed String


NSMutableAttributedString declares a number of methods for changing both characters and attributes, such as the primitive replaceCharactersInRange:withString: and setAttributes:range:, or the more convenient methods addAttribute:value:range:, applyFontTraits:range:, setAlignment:range:, and so on. All of the methods for changing a mutable attributed string properly update the mapping between characters and attributes, but after a change some inconsistencies can develop. Here are some examples of attribute consistency requirements:

NSMutableAttributedString defines methods to fix these inconsistencies as changes are made. This allows the attributes to be cleaned up at a low level, hiding potential problems from higher levels and providing for very clean update of display as attributes change. There are six methods for fixing attributes:

The first method, fixAttributesInRange:, invokes the other three fix... methods to clean up deleted attachment references, font attributes, and paragraph attributes, respectively. The individual method descriptions explain what cleanup entails for each case.

The beginEditing and endEditing methods are provided for subclasses of NSMutableAttributedString to override. Their default implementations do nothing. These methods allow instances of a subclass to record or buffer groups of changes and clean themselves up on receiving an endEditing message. endEditing also allows the receiver to notify any observers that it has been changed. NSTextStorage's implementation of endEditing, for example, fixes changed attributes and then notifies its NSLayoutManagers that they need to re-lay and redisplay their text.


RTF Document Attributes


Attributed strings keep attribute information for their text only, while RTF allows for more general attributes of a document, especially regarding paper size and layout. To support higher-level objects that use attributed strings, the methods that work with RTF also read and write some RTF directives for document attributes, stored in an NSDictionary under these keys:


Attribute KeyValue Class
PaperSizeNSValue, as an NSSize
LeftMarginNSNumber, as a float
RightMarginNSNumber, as a float
TopMarginNSNumber, as a float
BottomMarginNSNumber, as a float

The init methods, such as initWithRTF:documentAttributes:, return by reference a dictionary containing the attributes read from the RTF data, which your application can then use to set up its page layout. Similarly, RTF extraction methods such as RTFDFromRange:documentAttributes:, accept a dictionary containing those attributes and writes them into the RTF data, thus preserving the page layout information.


Attachments


Attachments, such as embedded images or files, are represented in an attributed string by both a special character and an attribute. The character is identified by the global name NSAttachmentCharacter, and indicates the presence of an attachment at its location in the string. The attribute, identified in the string by the attribute name NSAttachmentAttributeName, is an NSTextAttachment object. An NSTextAttachment contains the data for the attachment itself, as well as an image to display when the string is drawn. You can use NSAttributedString's attributedStringWithAttachment: class method to construct an attachment string, which you can then add to a mutable attributed string using appendAttributedString: or insertAttributedString:atIndex:.


Table of Contents