如何使用NSCoding序列化C数组?

时间:2015-02-25 02:26:41

标签: objective-c nscoding


我有一个具有C数组属性的Objective-C类 我想用NSCoding序列化该属性。

@interface TestClass : NSObject <NSCoding>
@property (nonatomic) int* intArray;
@end

@implementation TestClass
-(instancetype)init
{
    self = [super init];
    if (self) {
        _intArray = (int *)malloc(sizeof(int) * 5);
        for (int i = 0; i < 5; i++) {
            _intArray[i] = 0;
        }
    }
    return self;
}
-(void)dealloc
{
    free(_intArray);
}
-(instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        //???
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder *)coder
{
    //???
}
@end

我应该写什么? 谢谢。

修改
谢谢你的回答 但是我应该使用decodeArrayOfObjCType:count:at:或NSData?
如果我不知道数组的数量,我不能使用decodeArrayOfObjCType:count:at:method?

-(instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        _itemCount = [coder decodeIntForKey:kItemCount];
        _intArray = (int *)malloc(sizeof(int) * _itemCount);
        [coder decodeArrayOfObjCType:@encode(int) count:_itemCount at:_intArray];
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder *)coder
{
    [coder encodeInt:_itemCount forKey:kItemCount];
    [coder encodeArrayOfObjCType:@encode(int) count:_itemCount at:_intArray];
}

-(instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        _itemCount = [coder decodeIntForKey:kItemCount];
        NSData *data = [coder decodeObjectForKey:kIntArray];
        if (data) {
            NSUInteger length = [data length];
            _intArray = (int *)malloc(length);
            [data getBytes:_intArray length:length];
        }
    }
    return self;
}

-(void)encodeWithCoder:(NSCoder *)coder
{
    [coder encodeInt:_itemCount forKey:kItemCount];
    if (_intArray) {
        NSData *data = [NSData dataWithBytes:_intArray length:sizeof(int) * _itemCount];
        [coder encodeObject:data forKey:kIntArray];
    }
}

谢谢。

2 个答案:

答案 0 :(得分:5)

如果您在解码时不知道阵列中有多少个值,那么您可能想要使用NSData。因此,您可能有两个属性,一个用于intData,另一个用于数组中count项:

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        NSData *data = [coder decodeObjectForKey:kIntArrayKey];
        if (data) {
            NSUInteger length = [data length];
            self.count = length / sizeof(int);
            self.intArray = (int *)malloc(length);
            [data getBytes:_intArray length:length];
        }
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
    if (_intArray) {
        NSData *data = [NSData dataWithBytesNoCopy:self.intArray length:sizeof(int) * self.count freeWhenDone:NO];
        [coder encodeObject:data forKey:kIntArrayKey];
    }
}

或者,如果您不想使用NSData,则可以使用encodeBytes:length:forKey:

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        NSUInteger length;
        const uint8_t *bytes = [coder decodeBytesForKey:kIntArrayKey returnedLength:&length];
        if (bytes) {
            self.count = length / sizeof(int);
            self.intArray = (int *)malloc(length);
            memcpy(_intArray, bytes, length);
        }
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
    if (_intArray) {
        [coder encodeBytes:(void *)self.intArray length:sizeof(int) * self.count forKey:kIntArrayKey];
    }
}

档案和序列化编程指南Encoding and Decoding C Data Types概述了一些其他注意事项:

  

简单类型的数组

     

如果要编码一个字节数组,可以使用提供的方法来执行此操作。

     

对于其他算术类型,请使用数组创建NSData对象。请注意,在这种情况下,处理平台字节序问题是您的责任。平台字节序可以通过两种通用方式处理。第一种技术是将数组的元素(或者更确切地说,数组的临时副本)转换为规范的字节序,大或小,一次一个,具有在通用二进制编程指南中交换字节中讨论的函数,第二种版本(另请参阅Foundation Functions Reference中的“字节排序”)并将结果作为缓冲区提供给NSData。 (或者,您可以使用encodeBytes:length:forKey:直接写入字节。)在解码时,您必须反转该过程,从大或小端规范形式转换为当前主机表示。另一种技术是按原样使用数组并记录单独的键控值(可能是布尔值),即创建存档时主机的字节顺序。在解码期间,读取endian键并将其与当前主机的字节序进行比较,并仅在不同时交换值。

     

或者,您可以将每个数组元素分别归档为其本机类型,可能使用受数组语法启发的键名称,如“theArray[0]”“theArray[1]”等。这不是一种非常有效的技术,但您可以忽略端点问题。

答案 1 :(得分:4)

-(instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        _intArray = (int *)malloc(sizeof(int) * 5);
        [coder decodeArrayOfObjCType:@encode(int) count:5 at:_intArray];
    }
    return self;
}

-(void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeArrayOfObjCType:@encode(int) count:5 at:_intArray];
}