有一種方式來保存自定義屬性使用可可爲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;
// Convert the attributed string to RTF
if ((rtfData = [text RTFFromRange:NSMakeRange(0, [text length]) documentAttributes:nil]) == nil)
return(nil);
// Find and encode your custom attributes here. In this example the data is a string and there's at most one of them
if ((customData = [text attribute:@"MyCustomData" atIndex:0 effectiveRange:&range]) == nil)
return(rtfData); // No custom data, return RTF as is
dataLocation = range.location;
// Get a string representation of the RTF
rtfString = [[NSMutableString alloc] initWithData:rtfData encoding:NSASCIIStringEncoding];
// Find the anchor where we'll put our data, namely just before the first paragraph property reset
range = [rtfString rangeOfString:@"\\pard" options:NSLiteralSearch];
if (range.location == NSNotFound)
{
NSLog(@"Custom data dropped; RTF has no paragraph properties");
[rtfString release];
return(rtfData);
}
// Insert the starred group containing the custom data and its location
encodedData = [NSString stringWithFormat:@"{\\*\\my_custom_keyword %d,%@}\n", dataLocation, customData];
[rtfString insertString:encodedData atIndex:range.location];
// Convert the amended RTF back to a data object
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;
// Find the custom data and its end
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;
}
// Get the location and the string data, which are separated by a comma
range.length = endRange.location - range.location;
components = [[rtfString substringWithRange:range] componentsSeparatedByString:@","];
[rtfString release];
// Assign the custom data back to the attributed string. You should do range checking here (omitted for clarity)
[text addAttribute:@"MyCustomData" value:[components objectAtIndex:1]
range:NSMakeRange([[components objectAtIndex:0] integerValue], 1)];
}
當然,這些數據不會是RTF格式,所以您不應該給文件擴展名爲.rtf。最好彌補新的擴展和UTI並將其稱爲新格式。 – 2010-04-13 06:39:29
這是一個很好的答案!感謝Rob和Peter。我可以在沒有輸出爲rtf或rtfd的情況下生活。我想在完成新計劃之後我並沒有想過......我應該自己想到NSCoder。 – regulus6633 2010-04-13 07:44:51
這在iOS中對我來說不太適用。我碰到一個NSCFType encodeWithCoder:,其中的類型對象如下所示: [(kCGColorSpaceDeviceRGB)](0.576471 0.576471 0.560784 1) - 如果您碰巧知道如何我可以編碼這些? –
2013-06-20 20:01:29