理解NSAttributedString

n NSAttributedString object manages character strings and associated sets of attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string.

這句話就是對這個類的一個最簡明扼要的概括。NSAttributedString管理一個字符串,以及與該字符串中的單個字符或某些範圍的字符串相關的屬性。比如這個字符串“北京天安門”,“我”跟其他字符的顏色不一樣,而“北京”與其他的字體和大小不一樣,等等。NSAttributedString就是用來存儲這些信息的,具體實現時,NSAttributedString維護了一個NSString,用來保存最原始的字符串,另有一個NSDictionary用來保存各個子串/字符的屬性。

Create Attributed String

有3種方法創建Attributed String。

1. 使用initWithString:, initWithString:attributes:, 或者 initWithAttributedString: ,下面是一個實例代碼:

1
2
3
4
5
NSFont *font = [NSFont fontWithName:@"Palatino-Roman" size:14.0];
NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:font
                                    forKey:NSFontAttributeName];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"strigil"
            attributes:attrsDictionary];

 可以看到上面創建的整個字符串關聯了Font屬性。如果希望只是對某一範圍的字符串施加某個屬性應該使用NSMutableAttributedString的 setAttributes:range:方法。這裏例子是使用了Font屬性,在Appkit中特殊定義了若干屬性,這些屬性被用於Core Text中。其他的屬性包括前景色、背景色、是否有shadow等,具體可見本文

2. 使用initWithRTF:documentAttributes:, initWithRTFD:documentAttributes:, and initWithRTFDFileWrapper:documentAttributes:從rich text (RTF) 或者 rich text with attachments (RTFD) 數據中創建。

複製代碼
NSData *rtfData = ...;  // assume rtfData is an NSData object containing valid RTF data
NSDictionary *docAttributes;
NSSize paperSize;
 
NSAttributedString *attrString;
 
if ((attrString = [[NSAttributedString alloc]
        initWithRTF: rtfData documentAttributes: &docAttributes])) {
 
    NSValue *value = [docAttrs objectForKey:@"PaperSize"];
    paperSize = [value sizeValue];
    // implementation continues...
複製代碼

3. 使用initWithHTML:documentAttributes: 和 initWithHTML:baseURL:documentAttributes:從HTML數據中創建。有線程安全問題,使用時需要注意。

對RTF和HTML的支持都是AppKit對NSAttributedString的擴展。

Accessing Attributes

從上面對這個類的介紹可以知道,如果我們要訪問某個子串/字符的屬性,需要提供子串的位置和屬性的名字,而如果不提供屬性名字,那就把所有屬性都返回。下面就是其對應的APIs:

1
2
3
4
5
6
attributesAtIndex:effectiveRange:
attributesAtIndex:longestEffectiveRange:inRange:
attribute:atIndex:effectiveRange:
attribute:atIndex:longestEffectiveRange:inRange:
fontAttributesInRange:
rulerAttributesInRange:

 fontAttributesInRange: 和 rulerAttributesInRange: 是由AppKit擴展的屬性。

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.

Methods that return an effective range by reference are not guaranteed to return the maximal range to which the attribute(s) apply; they are merely guaranteed to return some range over which they apply. In practice they will return whatever range is readily available from the attributed string's internal storage mechanisms, which may depend on the implementation and on the precise history of modifications to the attributed string.

那些用reference返回有效範圍的方法並不保證一定返回attribute應用的最大範圍。它們只保證返回那些attribute有效的一些範圍。實際上,它們只是返回attributed string中容易返回的那些信息,是否容易與內部實現,已經對attributed string的精確修改歷史有關。

Methods that return a longest effective range by reference, on the other hand, are guaranteed to return the longest range containing the specified index to which the attribute(s) in question apply (constrained by the value of the argument passed in forinRange:). For efficiency, it is important that the inRange: argument should be as small as appropriate for the range of interest to the client.

那些返回最長有效範圍的方法時能夠保證返回制定attribute有效的最長的range的。爲了效率,inRange: 參數應該儘量小,能滿足客戶需要就好。

When you iterate over an attributed string by attribute ranges, either sort of method may be appropriate depending on the situation. If there is some processing to be done for each range, and you know that the full range for a given attribute is going to have to be handled eventually, it may be more efficient to use the longest-effective-range variant, so as not to have to handle the range in pieces. However, you should use the longest-effective-range methods with caution, because the longest effective range could be quite long—potentially the entire length of the document, if the inRange: argument is not constrained.

 

Changing an Attributed String

NSMutableAttributedString提供若干方法,即可以修改字符串,又可以修改字符串的屬性。經過多次修改後,有些信息可能變的不一致了,爲了讓信息保持一致,可以使用下面的方法:

1
2
3
4
5
6
fixAttributesInRange:
fixAttachmentAttributeInRange:
fixFontAttributeInRange:
fixParagraphStyleAttributeInRange:
beginEditing
endEditing

 

這些方法都是AppKit的擴展功能。

 

Reference:

1. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/AttributedStrings/AttributedStrings.html#//apple_ref/doc/uid/10000036-BBCCGDBG 

2. https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSAttributedString_AppKitAdditions/Reference/Reference.html#//apple_ref/doc/uid/20000167-BAJJCCFC

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章