根据this question的接受答案,我写了以下代码:
NSData* somedata;
somedata=[NSKeyedArchiver archivedDataWithRootObject:ts];
其中ts是一个NSAttributedString,它填充了一些文本和一些属性(在本例中为颜色)。
当我执行此代码时,收到此错误:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x6eb5b90'
我是NSCoder竞技场的新手,但上述问题的答案使我觉得这就是我必须要做的。是吗?我错过了什么吗?
编辑:
在这种情况下,无法识别的选择器被发送到NSAttributedString中的颜色属性。当我像这样初始化字符串时:
NSAttributedString *ts = [[NSAttributedString alloc] initWithString:text attributes:self.currentAttributeDictionary];
字典的构建如下:
self.currentAttributeDictionary=[NSDictionary dictionaryWithObjectsAndKeys:
[self.currentColor CGColor],(NSString*)kCTForegroundColorAttributeName,
nil];
字典的NSLog产生了这个:
New dictionary is: {
CTForegroundColor = "<CGColor 0x6eb5b90> [<CGColorSpace 0x6e968c0> (kCGColorSpaceDeviceRGB)] ( 1 1 0 1 )";}
上面的CGColor地址与错误消息中的地址相匹配。
答案 0 :(得分:6)
虽然UIColor
符合NSCoding
,但它(与大多数此类不同)不免费桥接到CGColorRef
。您的字典正在尝试对其内容进行编码,CGColorRef
不知道如何编码自己。
假设您不想编码UIColor
(因为这些听起来像Core Text属性),您将不得不自己处理CGColorRef
的序列化。例如,请参阅this question了解一些有用的想法。
应该注意的是,顺便说一句,因为我不知道归档数据的去向,如果你想取消归档OS X上的数据,颜色再次成为AppKit / UIKit级别的头疼:{{1 }}和NSColor
不是直接兼容的,因此您仍然需要通过UIColor
,根据需要隐藏颜色空间信息。
答案 1 :(得分:0)
根据要求,这是我用来完成我需要完成的代码。自从我查看这段代码已经过去了一年,而且更多的是为了理解正在发生的事情,而不是为了实现优秀的编码实践或任何效率。但是,它确实有效,而且效果很好!
我在下面定义了一类NSAttributedString代码。
使用示例:
-(void)code:(id)sender {
self.testData=[textView.attributedString customEncode];
NSLog(@"%@",self.testData);
}
-(void)recover:(id)sender {
NSAttributedString* tString=[NSMutableAttributedString customDecode:self.testData];
NSLog(@"Recover pressed: %@",tString);
textView.attributedString=tString;
}
这是底层代码:
#import "NSAttributedString+Extras.h"
#import <CoreText/CoreText.h>
@implementation NSAttributedString (Extras)
-(NSData*)customEncode {
__block NSMutableArray* archivableAttributes=[[NSMutableArray alloc]init];
[self enumerateAttributesInRange:NSMakeRange(0, [self length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
NSLog(@"range: %d %d",range.location, range.length);
NSLog(@"dict: %@",attrs);
NSLog(@"keys: %@", [attrs allKeys]);
NSLog(@"values: %@", [attrs allValues]);
NSMutableDictionary* tDict=[[NSMutableDictionary alloc]init];
[tDict setObject:[NSNumber numberWithInt:range.location] forKey:@"location"];
[tDict setObject:[NSNumber numberWithInt:range.length] forKey:@"length"];
for (NSString* tKey in [attrs allKeys]) {
if ([tKey isEqualToString:@"CTUnderlineColor"]) {
[tDict setObject:[NSAttributedString arrayFromCGColorComponents:((CGColorRef)[attrs objectForKey:@"CTUnderlineColor"])] forKey:@"CTUnderlineColor"];
}
if ([tKey isEqualToString:@"NSUnderline"]) {
NSNumber* underline=[attrs objectForKey:@"NSUnderline"];
[tDict setObject:underline forKey:@"NSUnderline"];
}
if ([tKey isEqualToString:@"CTForegroundColor"]) {
[tDict setObject:[NSAttributedString arrayFromCGColorComponents:((CGColorRef)[attrs objectForKey:@"CTForegroundColor"])] forKey:@"CTForegroundColor"];
}
if ([tKey isEqualToString:@"NSFont"]) {
CTFontRef font=((CTFontRef)[attrs objectForKey:@"NSFont"]);
NSDictionary* fontDict=[NSDictionary
dictionaryWithObjects:
[NSArray arrayWithObjects:(NSString*)CTFontCopyPostScriptName(font),[NSNumber numberWithFloat:CTFontGetSize(font)], nil]
forKeys:
[NSArray arrayWithObjects:@"fontName", @"fontSize", nil]];
[tDict setObject:fontDict forKey:@"NSFont"];
}
}
[archivableAttributes addObject:tDict];
}];
NSMutableDictionary* archiveNSMString=[NSMutableDictionary
dictionaryWithObjects: [NSArray arrayWithObjects:[self string],archivableAttributes,nil]
forKeys:[NSArray arrayWithObjects:@"string",@"attributes",nil]];
NSLog(@"archivableAttributes array: %@",archiveNSMString);
NSData* tData=[NSKeyedArchiver archivedDataWithRootObject:archiveNSMString];
NSLog(@"tdata: %@",tData);
return tData;
}
+(NSAttributedString*)customDecode:(NSData *)data {
NSMutableAttributedString* tString;
NSMutableDictionary* tDict=[NSKeyedUnarchiver unarchiveObjectWithData:data];
NSArray* attrs;
CTFontRef font=NULL;
CGColorRef color=NULL;
NSNumber* underlineProp=[NSNumber numberWithInt:0];
CGColorRef underlineColor=NULL;
NSLog(@"decoded dictionary: %@",tDict);
if ([[tDict allKeys]containsObject:@"string"]) {
tString=[[NSMutableAttributedString alloc]initWithString:((NSString*)[tDict objectForKey:@"string"])];
}
else {
tString=[[NSMutableAttributedString alloc]initWithString:@""];
}
if ([[tDict allKeys]containsObject:@"attributes"]) {
attrs=[tDict objectForKey:@"attributes"];
}
else {
attrs=nil;
}
for (NSDictionary* attDict in attrs) {
int location=-1;
int length=-1;
NSRange insertRange=NSMakeRange(-1, 0);
if ([[attDict allKeys]containsObject:@"location"]) {
location=[[attDict objectForKey:@"location"]intValue];
}
if ([[attDict allKeys]containsObject:@"length"]) {
length=[[attDict objectForKey:@"length"]intValue];
}
if (location!=-1&&length!=-1) {
insertRange=NSMakeRange(location, length);
}
if ([[attDict allKeys]containsObject:@"NSUnderline"]) {
underlineProp=[attDict objectForKey:@"NSUnderline"];
}
if ([[attDict allKeys]containsObject:@"CTUnderlineColor"]) {
underlineColor=[NSAttributedString cgColorRefFromArray:[attDict objectForKey:@"CTUnderlineColor"]];
}
if ([[attDict allKeys]containsObject:@"CTForegroundColor"]) {
color=[NSAttributedString cgColorRefFromArray:[attDict objectForKey:@"CTForegroundColor"]];
}
if ([[attDict allKeys]containsObject:@"NSFont"]) {
NSString* name=nil;
float size=-1;
NSDictionary* fontDict=[attDict objectForKey:@"NSFont"];
if ([[fontDict allKeys]containsObject:@"fontName"]) {
name=[fontDict objectForKey:@"fontName"];
}
if ([[fontDict allKeys]containsObject:@"fontSize"]) {
size=[[fontDict objectForKey:@"fontSize"]floatValue];
}
if (name!=nil&&size!=-1) {
font=CTFontCreateWithName((CFStringRef)name, size, NULL);
}
}
if (insertRange.location!=-1) {
if (color!=NULL) {
[tString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)color range:insertRange];
}
if (font!=NULL) {
[tString addAttribute:(NSString*)kCTFontAttributeName value:(id)font range:insertRange];
}
if ([underlineProp intValue]!=0&&underlineColor!=NULL) {
[tString addAttribute:(NSString*)kCTUnderlineColorAttributeName value:(id)underlineColor range:insertRange];
[tString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:(id)underlineProp range:insertRange];
}
}
}
[tString enumerateAttributesInRange:NSMakeRange(0, [tString length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
NSLog(@"range: %d %d",range.location, range.length);
NSLog(@"dict: %@",attrs);
NSLog(@"keys: %@", [attrs allKeys]);
NSLog(@"values: %@", [attrs allValues]);
}];
return [[NSAttributedString alloc]initWithAttributedString:tString];
}
+(NSArray*)arrayFromCGColorComponents:(CGColorRef)color {
int numComponents=CGColorGetNumberOfComponents(color);
CGFloat* components=CGColorGetComponents(color);
NSMutableArray* retval=[[NSMutableArray alloc]init];
for(int i=0;i<numComponents;i++) {
[retval addObject:[NSNumber numberWithFloat:components[i]]];
}
return [NSArray arrayWithArray:retval];
}
+(CGColorRef)cgColorRefFromArray:(NSArray*)theArray {
CGFloat* array=malloc(sizeof(CGFloat)*[theArray count]);
for (int i=0; i<[theArray count]; i++) {
array[i]=[[theArray objectAtIndex:i]floatValue];
}
CGColorSpaceRef theSpace;
if ([theArray count]==2) {
theSpace=CGColorSpaceCreateDeviceGray();
}
else {
theSpace=CGColorSpaceCreateDeviceRGB();
}
return CGColorCreate(theSpace, array);
}
@end