2

有什么方法可以使用 an来对包含自定义结构的 anNSKeyedArchiver进行编码?NSValue我有一个NSDictionary包含包装的结构NSValues,我想将其存档为更大对象图的一部分,但我收到以下错误:

-[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 以获得相同的行为。

4

2 回答 2

1

There are issues with something to do with @encode and anonymous structs. Try changing the struct definition to:

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

If that doesn't work, you can wrap the struct using NSData:

[NSData dataWithBytes:&myPoint length:sizeof(MYPoint)];
于 2013-06-05T13:19:01.077 回答
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)];   

虚数

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 的内容被解释为指向 char 的指针,因此字符串中包含的前四个字节被视为指针(实际使用的字节数可能因硬件架构而异)。也就是说,序列“This”被解释为一个指针值,它不太可能是一个合法的地址。存储此类数据项的正确方法是使用 NSString 对象(如果您需要在对象中包含字符),或者传递其指针的地址,而不是指针本身:

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

这里传递了myCString的地址(&myCString),所以字符串的第一个字符的地址存放在theValue中。

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

于 2017-08-22T12:11:49.397 回答