使用NSData的自定义编码,初始化但崩溃



我花了一些时间调试这个问题,结果被难住了。

我正在尝试将自定义对象紧密地打包到NSData中,以在将它们保存到磁盘时节省空间。我已经为这些自定义对象实现了自定义编码和解码方法。当我打包和解包对象时,一切都会根据调试器正确初始化。代码运行后,它立即具有EXC_BAD_ACCESS code=1code=2

以下是编码和解码:

-(instancetype) initWithData:(NSData *)data {
    self = [super init];
    if (self) {
        _memConstants = [[DWMemoryConstants alloc]init];
        int arraySize = _memConstants.chunkSize * _memConstants.chunkSize;
        NSData* unencodedBlocks[arraySize];
        [data getBytes:unencodedBlocks];
        _blocks = [[NSMutableDictionary alloc]init];
        for (int i = 0; i < 10; i++) {
            DWBlock *block = [[DWBlock alloc]initWithData:unencodedBlocks[i]];
            [_blocks setObject:block forKey:[NSValue valueWithCGPoint:CGPointFromString(block.blockName)]];
            if (i == 0) {
                _position = CGPointFromString(block.chunkName);
            }
        }
        _chunkName = NSStringFromCGPoint(_position);
        _bounds = CGRectMake(_position.x * _memConstants.chunkSize * kBlockSpriteWidth,
                             _position.y * _memConstants.chunkSize * kBlockSpriteWidth,
                             _memConstants.chunkSize * kBlockSpriteWidth,
                             _memConstants.chunkSize * kBlockSpriteWidth);
    }
    return self;
}
-(NSData *) customEncode {
    NSMutableData *data = [[NSMutableData alloc]init];
    NSData* blocks[_blocks.allValues.count];
    int count = 0;
    for (DWBlock *block in _blocks.allValues) {
        blocks[count] = [block customEncode];
        count++;
    }
    [data appendBytes:&blocks length:sizeof(blocks)];
    return data;
}

异常发生在该代码的末尾。它首先成功地打印了所有的日志消息,我已经验证了Chunk对象没有任何问题:

-(void) testEncodeDecode {
    DWChunk *testChunk = [[DWChunk alloc]initWithPosition:CGPointMake(100, 100)];
    NSData *testData = [testChunk customEncode];
    NSLog(@"datasize= %@", testData);
    DWChunk *unencodedChunk = [[DWChunk alloc]initWithData:testData];
    NSLog(@"blocks=%@", unencodedChunk.blocks.allValues);
    NSLog(@"this message will print");
}

正如我所说,Chunk和Block对象的所有变量都已正确初始化。我怀疑这个问题与物体释放不当有关,但我不知道该怎么办。

编辑:我已经启用了僵尸检查,现在我收到了以下错误消息:

2014-10-24 11:38:31.775 DigWorld[10622:60b] *** -[NSConcreteMutableData release]: message sent to deallocated instance 0x81790710

编辑:我最初的想法在技术上是错误的(读代码太快…),但实际的错误是完全相同的。通过保存blocks,您只保存指针数组,而不保存实际数据。你可以确保:在你的评论中,你说sizeof(blocks)=3600_blocks.allValues.count=900,所以你只保存900个指针(*4字节/指针=3600字节)

[block customEncode]创建的实际数据然后由ARC处理

之后读取此数组时,您将获得指向已标记为已释放的内存片段(以前的NSData)的指针,从而导致崩溃,并解释启用僵尸时的错误消息。

棘手的部分:由于这是程序的同一个实例,并且编码和解码是相邻运行的,因此实际内存没有被重新分配/覆盖。因此,您会得到对象保存正确的印象。但请放心,这段记忆最终会被其他东西覆盖。您可以通过将NSData保存在磁盘上并在重新运行程序时对其进行解码来确保这一点。


在我看来,你似乎在试图重新发明这里的轮子。NSCoding协议正是为了这个目的而创建的:在磁盘上持久化对象的图形。NSKeyedArchiver类将在一个经过良好测试和文档化的界面中,以灵活性和平台独立性为您提供磁盘串行化。

您应该利用该体系结构。即使您认为NSKeyedArchiver创建的归档对于您的目的来说太"大",也要使用现有的体系结构并创建自己的归档器。

如果你选择这样做,你可以从这个开源的NSCoder子类实现中获得灵感(免责声明:我写的)

最新更新