2013-06-05 35 views
1

有什么办法可以使用NSKeyedArchiver来编码包含自定义结构的NSValue ?.我有一个NSDictionary包含结构包裹在NSValues我要存档这是一种大型的对象图的一部分,但我收到以下错误:NSKeyedArchiver:如何归档包含自定义结构的NSValue

-[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs 

然而,考虑以下因素:

//Copy of the CGPoint declaration 
struct MYPoint { 
    CGFloat x; 
    CGFloat y; 
}; 
typedef struct MYPoint MYPoint; 

CGPoint point = {1.0, 1.0}; 
MYPoint myPoint = {1.0, 1.0}; 

NSLog(@"CGPoint: %s", @encode(CGPoint)); //CGPoint: {CGPoint=ff} 
NSLog(@"MYPoint: %s", @encode(MYPoint)); //MYPoint: {MYPoint=ff} 

NSValue *CGPointValue = [NSValue valueWithBytes:&point objCType:@encode(CGPoint)]; 
NSData *CGPointData = [NSKeyedArchiver archivedDataWithRootObject:CGPointValue]; 
//NO ERROR  

NSValue *MYPointValue = [NSValue valueWithBytes:&myPoint objCType:@encode(MYPoint)]; 
NSData *MYPointData = [NSKeyedArchiver archivedDataWithRootObject:MYPointValue]; 
//ERROR: -[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs 

这个存档器不能编码你的结构”是这样的情况,这是故事的结局还是有可能获得相同的行为,但为定制结构可以得到CGPoint

我将只创建一个包装了NSValue并实现NSCoding解决它一个小的自定义对象,但我很好奇在代码CGPoint和奇迹上面显示的矛盾如果有NSValue延伸到路得到相同的行为。

回答

1

存在与@encode和匿名结构有关的问题。尝试改变结构定义:

typedef struct MYPoint { 
    CGFloat x; 
    CGFloat y; 
} MYPoint; 

如果不工作,你可以用使用NSData的结构:

[NSData dataWithBytes:&myPoint length:sizeof(MYPoint)]; 
+0

感谢您的回答。替代的结构定义不能解决错误。关心使用'NSData'替代'NSValue'来封装结构。你知道他们是否有任何可移植性考虑?归档数据最终可能通过iCloud/Game Center在设备(OSX和iOS)之间移动。 –

+1

是的,可能存在处理器之间的可移植性问题,具有不同的排列顺序...... – Wain

0

下面的例子说明编码定制的C结构。

//assume ImaginaryNumber defined: 
    typedef struct { 
      float real; 
      float imaginary; 
    } ImaginaryNumber; 
      ImaginaryNumber miNumber; 
    miNumber.real = 1.1; 
    miNumber.imaginary = 1.41; 
    NSValue *miValue = [NSValue valueWithBytes: &miNumber withObjCType:@encode(ImaginaryNumber)]; 

ImaginaryNumber

miNumber2; 
[miValue getValue:&miNumber2 

];

您指定的类型必须具有恒定的长度。您不能在NSValue中存储C字符串,可变长度数组和结构以及其他不确定长度的数据类型 - 您应该为这些类型使用NSString或NSData对象。你可以在NSValue对象中存储一个指向变长项目的指针。以下代码摘录错误地尝试C字符串直接放入一个NSValue对象:

/* INCORRECT! */ 
char *myCString = "This is a string."; 
NSValue *theValue = [NSValue valueWithBytes:myCString withObjCType:@encode(char *)]; 

在此代码摘录myCString的内容被解释为一个指向炭,所以包含在所述字符串中的前四个字节被视为指针(实际使用的字节数可能因硬件架构而异)。也就是说,序列“This”被解释为一个指针值,这不太可能是合法地址。存储这样的数据项的正确方法是使用一个NSString对象(如果你需要包含在一个对象中的字符),或通过其指针的地址,而不是指针本身:

/* Correct. */ 
char *myCString = "This is a string."; 
NSValue *theValue = [NSValue valueWithBytes:&myCString withObjCType:@encode(char **)]; 

这里传递myCString的地址(& myCString),因此字符串的第一个字符的地址存储在值中。

重要提示:NSValue对象不会复制字符串的内容,而是复制指针本身。如果使用分配的数据项创建NSValue对象,则在NSValue对象存在时不要释放数据的内存。