使用Cocoa可以将自定义属性保存至RTF。这是因为RTF是一种文本格式,即使您不知道所有RTF规则并且没有自定义的RTF读写器,也可以将其作为字符串进行操作。我在下面概述的过程中对RTF进行了后处理,我个人已经使用了这种技术。需要非常小心的一件事情是,插入到RTF中的文本仅使用7位ASCII和没有未转义的控制字符,包括“\ { } ”。
以下是将数据编码的方法:
NSData *GetRtfFromAttributedString(NSAttributedString *text)
{
NSData *rtfData = nil;
NSMutableString *rtfString = nil;
NSString *customData = nil, *encodedData = nil;
NSRange range;
NSUInteger dataLocation;
if ((rtfData = [text RTFFromRange:NSMakeRange(0, [text length]) documentAttributes:nil]) == nil)
return(nil);
if ((customData = [text attribute:@"MyCustomData" atIndex:0 effectiveRange:&range]) == nil)
return(rtfData);
dataLocation = range.location;
rtfString = [[NSMutableString alloc] initWithData:rtfData encoding:NSASCIIStringEncoding];
range = [rtfString rangeOfString:@"\\pard" options:NSLiteralSearch];
if (range.location == NSNotFound)
{
NSLog(@"Custom data dropped; RTF has no paragraph properties");
[rtfString release];
return(rtfData);
}
encodedData = [NSString stringWithFormat:@"{\\*\\my_custom_keyword %d,%@}\n", dataLocation, customData];
[rtfString insertString:encodedData atIndex:range.location];
rtfData = [rtfString dataUsingEncoding:NSASCIIStringEncoding];
[rtfString release];
return(rtfData);
}
这种技术的原理是,所有符合标准的RTF阅读器都会忽略它们无法识别的“星号组”。因此,您要确保您的控制字符不会被任何其他阅读器识别出来,所以使用一些独特的前缀,比如您公司或产品的名称,这样更容易区分。如果您的数据很复杂、二进制或可能包含非法的RTF字符,而你又不想转义,那么可以使用base64编码。记得在关键字后面加上一个空格。
类似地,在读取RTF文件时,您需要搜索您的控制字符,提取数据并恢复属性。这个程序需要传入带属性的字符串和其来源的RTF文件作为参数。
void RestoreCustomAttributes(NSMutableAttributedString *text, NSData *rtfData)
{
NSString *rtfString = [[NSString alloc] initWithData:rtfData encoding:NSASCIIStringEncoding];
NSArray *components = nil;
NSRange range, endRange;
range = [rtfString rangeOfString:@"{\\*\\my_custom_keyword " options:NSLiteralSearch];
if (range.location == NSNotFound)
{
[rtfString release];
return;
}
range.location += range.length;
endRange = [rtfString rangeOfString:@"}" options:NSLiteralSearch
range:NSMakeRange(range.location, [rtfString length] - endRange.location)];
if (endRange.location == NSNotFound)
{
[rtfString release];
return;
}
range.length = endRange.location - range.location;
components = [[rtfString substringWithRange:range] componentsSeparatedByString:@","];
[rtfString release];
[text addAttribute:@"MyCustomData" value:[components objectAtIndex:1]
range:NSMakeRange([[components objectAtIndex:0] integerValue], 1)];
}
CGColorRef
不符合NSCoding
。请参考这个答案:http://stackoverflow.com/a/10558963/50122 - Rob KenigerCGColorRef
不是一个 Objective-C 对象,它是一个 C 结构体,因此类别的概念并不真正适用。 - Rob Keniger