【问题标题】:How to serialize C array with NSCoding?如何使用 NSCoding 序列化 C 数组?
【发布时间】:2015-02-25 02:26:40
【问题描述】:


我有具有 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: 方法?

-(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];
    }
}

谢谢。

【问题讨论】:

    标签: objective-c nscoding


    【解决方案1】:

    如果您不知道解码时数组中有多少个值,那么您可能需要使用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: 直接写入字节。)在解码时,您必须反转该过程,从大端或小端规范形式转换为当前主机表示。另一种技术是按原样使用数组并以单独的键值(可能是布尔值)记录创建档案时主机的字节顺序。在解码过程中,读取字节序键并将其与当前主机的字节序进行比较,如果不同则交换值。

    或者,您可以将每个数组元素分别归档为它们的原生类型,或许可以使用受数组语法启发的键名,例如“theArray[0]”“theArray[1]” 等。这不是一种非常有效的技术,但您可以忽略字节序问题。

    【讨论】:

    • 感谢您的回答。如果我在解码时不知道数组的计数,那么我不能使用 decodeArrayOfObjCType:count:at: 方法?请阅读我编辑的评论。谢谢。
    • 我不明白你如何使用decodeArrayOfObjCType,除非你事先知道count。这就是我建议encodeObject 方法的原因。你也可以使用encodeBytes
    • @noprops 只是先对计数进行编码,然后再对数组中的项目进行编码。然后当你解码时,你首先解码计数,然后你知道有多少。
    • @AbhiBeckert 但是decodeArrayOfObjCType 没有key。当其中一个不带键时,如何对多个值进行编码?
    • @Rob 如果您直接使用NSCoding,则没有密钥。仅当您使用不需要的 NSKeyedArchiver 时才存在密钥。请注意decodeArrayOfObjCTypeNSCoding 的一部分,在NSKeyedArchiver 中不存在。 NSCoding 只会在您每次解码时为您提供下一个值,其顺序与您编码的顺序相同。
    【解决方案2】:
    -(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];
    }
    

    【讨论】:

      猜你喜欢
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多