NSData, NSValue, NSKeyedArchiver and non objects

# Objective-C

做的一个Framework跟App整合到一起,因为用到了多线程,所以通信不可避免,但是Framework里又载入了一个C++的Plugin,里面有许多struct,在把这类struct变成对象序列化时遇到问题。
以前做的很傻,把struct的所有成员用NSDictionary来一个个封装,再一个个反序列化,好傻呀。要是struct定义变了,那代码就又要修改了~所以重构了一下,这里给出怎样对non object数据结构进行对象封装和序列化。

怎样进行封装是引用JongAm‘s一篇博文。
原文地址:http://jongampark.wordpress.com/2008/08/07/nsvalue-and-non-object-types/


当你想使用Cocoa的集合来存储非对象型数据时,NSValue和NSNumber是非常有用的。NSNumber是NSValue的子类,所以NSValue更灵活一些。
我们先看看NSValue能做什么:

所以下面的代码是可行的:

==========================================================================
==========================================================================

一个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:miNumber
  withObjCType:@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 {
  int dataSize;
  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,它已经提供好接口供你使用了。


谢谢!今天刚用到,弄了半天,早点看到就好了.用NSValue试了半天.保存CGSize不行.
后来改用NSData好了..
UIImage *currentImg = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",i]];
CGSize imageSize = currentImg.size;            
NSData *pointObjectIn = [NSData dataWithBytes:&imageSize length:sizeof(CGSize)];
[persistentArray addObject:pointObjectIn];  

NSData* getImgeData = [arrayImageCGSize objectAtIndex:i] ;
CGSize imageSize = *(CGSize*)[getImgeData bytes];

我有个问题向请教下,我用NSMutableData装载一个struct:
typedef struct pkg{
    char head1;
    char head2;
     int h_type;
     int h_version;
     int h_remark;
     int h_len;
     
} head;
然后用NSOutoutStream的write方法发送出去,为什么这个[NSData bytes]只把前面2个char发出去了,后面4个int都空了啊,相关代码如下:

head headP ; 
    NSLog(@"*headP:%d",sizeof(headP));

    headP.head1='A';
    headP.head2='B';
    headP.h_type=1;
    headP.h_version=0;
    headP.h_remark=0;
    headP.h_len=0;
    
    NSLog(@"*headP:%d",sizeof(headP));
    NSMutableData* headData=[NSMutableData dataWithBytes:(void *)&headP length:sizeof(headP)];
    [self writeToServer:[headData bytes]]; 
}
-(void) writeToServer:(const uint8_t *) buf {
    NSLog(@"write.maxLen:%d",sizeof(buf));
   [oStream write:buf maxLength:sizeof(buf)];
}
 
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值