【问题标题】:NSKeyedUnarchiver unarchiveObjectWithFile decodeBytesForKey EXC_BAD_ACCESS code=1 when retrieving data检索数据时 NSKeyedUnarchiver unarchiveObjectWithFile decodeBytesForKey EXC_BAD_ACCESS code=1
【发布时间】:2014-06-16 20:36:32
【问题描述】:

我需要一些关于使用 NSKeyedUnarchiver unarchiveObjectWithFile decodeBytesForKey 的帮助。我似乎正确地编写了所有内容,但读取数据给了我一个 EXC_BAD_ACCESS 错误。我正在尝试反序列化数据,并且对那里的各种答案和示例感到困惑。有人可以指出我做错了什么吗?

for (NSString *item in directoryContent){
    if ([[item pathExtension] isEqualToString:@"template"]) {

        **// Next line is the problem line from the calling code:**
        templateToRead = [[NSKeyedUnarchiver unarchiveObjectWithFile:[documentsDirectory stringByAppendingPathComponent:item]] mutableCopy];

        IDImageTemplate *template = [[IDImageTemplate alloc] init];
        template.templateData = templateToRead.templateData;
        template.templateQuality = templateToRead.templateQuality;
        template.templateSize = templateToRead.templateSize;
        template.templateLocation = templateToRead.templateLocation;
        [templatesRead addTemplate:template];
    }
}



- (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeInteger:self.templateSize forKey:@"templateSize"];
    [encoder encodeBytes:(const unsigned char*)self.templateData length:self.templateSize forKey:@"templateData"];
    [encoder encodeInt:self.templateQuality forKey:@"templateQuality"];
    [encoder encodeInt:self.templateLocation forKey:@"templateLocation"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (self) {
        self.templateSize = [decoder decodeIntegerForKey:@"templateSize"];

        **// Next line is where the real problem is:**

        self.templateData = (const char *)[decoder decodeBytesForKey:@"templateData" returnedLength:(NSUInteger *)self.templateSize];        
        self.templateQuality = [decoder decodeIntForKey:@"templateQuality"];
        self.templateLocation = [decoder decodeIntForKey:@"templateLocation"];
    }
    return self;
}

如果我注释掉数据的编码器和解码器行,我会为其他所有内容返回正确的值,但我也需要数据。

【问题讨论】:

    标签: objective-c byte nscoder nskeyedunarchiver


    【解决方案1】:

    好的,这里有几个不同的问题。值得庆幸的是,如果您了解 C,它们大多很容易修复。(顺便说一句,您可能应该花一些时间 [重新] 学习 C,因为我的印象是,到目前为止,您只是掌握了 C 的基础知识。 Objective-C 并且对它的超集语言了解不多。)无论如何,除了其中一个之外,所有这些都与特定的行有关,所以我将它复制到这里并将其砍掉,以便更容易检查:

    self.templateData =
        (const char *)[decoder
                       decodeBytesForKey:@"templateData"
                       returnedLength:(NSUInteger *)self.templateSize];
    
    1. 虽然有一个更明显的问题,但可能导致这次特别崩溃的问题是:(NSUInteger *)self.templateSize。我猜您是在尝试获取 templateSize 属性的实例变量的地址,但这不起作用。如果您想传入该实例变量的地址,您实际上需要做的是&_instanceVariable&this->_instanceVariable(前者通常有效,因为Obj-C 允许不合格的实例变量访问)。 (注意:最后两个代码位中的一元&是地址运算符。)

      您编写的代码是错误的,因为它没有获取该属性的底层实例变量的地址,它只是将返回的大小转换为指针。所以如果返回0,则指针为0;如果返回4,则指针为4;如果它返回 42801,则指针为 42801(即,它只是指向那些将指向的任何内容,第一个为 NULL)。所以,最后,decodeBytesForKey:returnedLength: 正在尝试写入一个可能是也可能不是可用内存的地址。谢天谢地,这很容易解决。

    2. 您可以修复 #1,仅此一项就可以让它在技术上工作很短的时间,但它仍然是错误的。您还必须考虑到decodeBytesForKey:returnedLength: 返回的缓冲区是一个临时缓冲区——它只在编码器存在时才存在。这在decodeBytesForKey:returnedLength:NSKeyedUnarchiver 文档的讨论部分和NSCoder decodeBytesWithReturnedLength: 文档中提到。不幸的是,如果您没有找到完全正确的位置,则可能很容易错过该细节,但它返回一个 const 指针可能是结果具有临时生命周期的证据。无论如何,如果要保留该数据,则需要复制返回的缓冲区。

      您在聊天中提到templateData 属性本身就是char *,所以这意味着您可能想要分配一个相同大小的新内存块memcpy 缓冲区,并存储那。这显然与您知道也要释放缓冲区的假设相吻合。

      到目前为止,更简单的方法是使用 NSData 而不是指向某些内存的指针。您仍然可以将其编码为字节(这允许您给它一个密钥)并将其解码为字节,但是您可以让 NSData 来处理复制缓冲区并为您释放它。例如,

      NSUInteger size = 0;
      const char *buffer = [coder decodeBytesForKey:@"key" returnedLength:&size];
      NSData *data = [NSData dataWithBytes:buffer length:size];
      

      这样,NSData 对象和 ARC 依次为您处理。根据您的具体需求,这可能不是可取的,因此显然要确定对您的具体情况重要的内容。

    3. 这不是一个特定的问题,而是更多的冗余问题:您不必在对字节本身进行编码之前对字节的长度进行编码。这已经由编码器处理,因此它通过returnedLength: 参数(lengthp)返回其长度。因此,不需要对长度进行编码和解码的行。

    【讨论】:

    • 好的。让我来做这件事。我相信你是 100% 正确的。就在得到这个答案之前,我通过 Xcode 提示我修复指向 & 的指针。从我读过的所有内容来看,我一直在这条赛道上,但只是没有得到它。是的,我是 C 的菜鸟。感谢您的帮助,我会在短时间内将其标记为答案。
    • 好的。我们正在尝试将一个类写到一个文件中。该类包含四个属性:templateData(最终需要是 char * 以匹配外部调用)、int templateSize(这是数据的长度、NSUInteger templateQuality 和 int templateLocation。我的部分困惑是我没有t实现returnedLength意味着“返回”长度。哈哈!我傻了。
    • 发生了——没有人是完美的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多