一个NSValue对象是用来存储一个C或者Objective-C数据的简单容器。它可以保存任意类型的数据,比如int,float,char,当然也可以是指pointers, structures, and object ids。NSValue类的目标就是允许以上数据类型的数据结构能够被添加到集合里,例如那些需要其元素是对象的数据结构,如NSArray或者NSSet的实例。需要注意的是NSValue对象一直是不可枚举的。
所以下面的代码是可行的:
// assume ImaginaryNumber defined: typedef struct { float real; float imaginary; }ImaginaryNumber; ImaginaryNumber miNumber; miNumber.real = 1.1; miNumber.imaginary =1.41; NSValue *miValue = [NSValue value:miNumberwithObjCType:@encode(ImaginaryNumber)]; // encode using the type name ImaginaryNumber miNumber2; [miValue getValue:&miNumber2]; |
是不是影像很深刻呢?然而不管怎样,苹果的文档里有一行看起来有点含混的解释:
时刻记住你的struct类型必须是定长的。你不可以存储C字符串,不定长数组和结构和其他的一些不定长的数据类型到NSValue中去。你应该使用NSString或者NSData来存储此类不定长数据。当然你可以把一个指向变长对象的指针存储在NSValue对象中。这是什么意思呢?如果你的数据不是定长的会发生什么?它能被正确的存储下来吗?
typedef struct { int dataSize; char *data; int year; } myStructType1; |
当data指向一个字符数组时,它能被正确的编码吗?
回答是很简单的,它是变长的,所以它指向的数据不会被编码。
只有这个指针地址被编码了。所以,如果你有一个服务线程编码了一个myStructTyle1的数据发布出去,并释放了这快内存,那么客户线程拿到这个数据解码并试图获取data的原始数据时,那就只能得到data的指针地址,而不是数据内容。所以不要期望它能存储你的data。你应该使用NSData或者NSArchiver来代替NSValue以达到期望目标。
我们再看这个例子:
typedef struct { int age; int month; int day; } innerType; typedef struct { intdataSize; innerType *innerData; } myStructType2; |
恩,innerTyle是一个定长的类型变量,那么它会被正确编码吗?
不会,苹果的文档并没有说明此类情况。它依然只编码指针而不是内容。
所以在这种情况下,依然得使用NSData。
总结,使用NSValue只能是对那些没有变量是指针的struct。
Then how the NSValue stores? It is kind of shallow copy. Please read this.
Here the address of myCString is passed (&myCString), so the address of the first character of the string is stored in theValue. Note that the NSValue object doesn’t copy the contents of the string, but the pointer itself. If you create an NSValue object with an allocated data item, don’t deallocate its memory while the NSValue object exists.
===============================我是引用分割线=================
不管是NSValue还是NSData,都是可以对非对象进行编码存储的。但在我的工程里,线程之间通信的数据是需要进行序列化的,我使用了NSKeyedArchiver来序列化。
在使用过程中发现NSValue存储的数据不可被序列化,而NSData可以。我的struct是定长的。
所以最好包装时都使用NSData吧,如果时rect, point之类的倒是可以用NSvalue,它已经提供好接口供你使用了。