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

nop*_*ops 2 objective-c nscoding


我有Objective-C类有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
Run Code Online (Sandbox Code Playgroud)

我应该写什么?
谢谢.

编辑:
谢谢你的回答.
但是我应该使用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];
}
Run Code Online (Sandbox Code Playgroud)

要么

-(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];
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢.

Rob*_*Rob 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];
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您不想使用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];
    }
}
Run Code Online (Sandbox Code Playgroud)

编码和解码C数据类型的的归档和序列化编程指南列出了一些其他注意事项:

简单类型的数组

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

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

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