objective-c - 在非 ARC 代码中从 NSKeyedArchiver 中提取数据

标签 objective-c memory nskeyedarchiver

在我的非 ARC iOS 项目中,我有一个返回存档数据的方法:

- (NSData*) archivedData {
    NSMutableData* data = [[NSMutableData alloc] init];
    NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    // Encode the fields that must be archived:
    [archiver encodeObject:... forKey:...];
    ...
    [archiver finishEncoding];
    [archiver release];
    return [data autorelease];

由于 initForWritingWithMutableData: 已弃用,我修改了实现:

- (NSData*) archivedData {
    NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
    // Encode the fields that must be archived:
    [archiver encodeObject:... forKey:...];
    ...
    [archiver finishEncoding];
    NSData* data = [archiver encodedData];
    [archiver release];
    return data;

首先,我在返回编码的 NSData 对象之前调用了 autorelease,但这导致了错误的内存访问 (EXC_BAD_ACCESS)。没有 autorelease 一切似乎都工作正常。

我现在很困惑。由于我在返回数据之前释放归档器,因此我认为 autorelease 会保护 NSData 对象,不会在调用方法处理它之前释放它。我担心 NSData 对象可能会在没有调用 autorelease 的情况下释放归档器后立即被释放。不知何故,当我运行代码时,发生了相反的情况。

有人可以解释一下这种行为吗? 另外,如果我做错了什么,我想知道如何修复代码。

我知道静态方法 archivedDataWithRootObject:requiringSecureCoding:error: 但我无法轻松使用它,因为我在单独编码对象时没有根对象。使用根对象会破坏应用程序现有用户的兼容性(如果我理解正确的话)。

最佳答案

NSData* data = [archiver encodedData];

方法-encodedData不以allocnew开头,也不包含单词copy ,也不叫retain。这意味着您没有拥有它。您不得对其调用release。它不属于你。换句话说:你还没有在这个对象上放置一个保留;您不得对其调用释放。

然后您释放负责数据archiver。不再保证数据存在。解决此问题的方法是在释放 archiver 之前保留它:

NSData* data = [[archiver encodedData] retain];

这实际上与原始代码通过使用 +[NSMutableData alloc] 初始化 data 所做的事情相同。请注意“分配”一词。这赋予了数据所有权(保留)。

按照相同的命名约定,此方法 promise 返回调用者不需要释放的对象。 (通常最容易将其视为净保留计数为 0,但在很多情况下这并不完全正确。)

- (NSData*) archivedData { ... }

您已经对数据进行了保留,因此您需要对其进行平衡。然而,您希望该对象能够存活足够长的时间以便被返回。解决这个问题的方法是 -autorelease,就像原始代码一样:

return [data autorelease];

所以大家在一起:

- (NSData*) archivedData {
    NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
    // Encode the fields that must be archived:
    [archiver encodeObject:... forKey:...];
    ...
    [archiver finishEncoding];
    NSData* data = [[archiver encodedData] retain]; // Retain here
    [archiver release];
    archiver = nil; // It's good practice to nil values that are no longer valid
    return [data autorelease]; // autorelease here
}

我再也找不到 Apple 有用的内存管理规则页面,但它在 Three Magic Words 中进行了总结。 .

关于objective-c - 在非 ARC 代码中从 NSKeyedArchiver 中提取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64790539/

相关文章:

objective-c - 将两个 double 值转换为字符串,然后使用新字符串创建一个字符串

ios - 进入前台时出现 UIRefreshControl 错误

c - 读入缓冲区时内存泄漏

php - 发送 POST 数组和内存泄漏

ios - 尝试使用 NSKeyedArchiver.archiveRootObject 时,Xcode 因无法识别的选择器而崩溃

ios - 取消存档 SKSpriteNode 会破坏 iOS 7.1 中 Sprite 的 SKTexture,否则没问题

ios - UIView 中的 MPMoviePlayerController

objective-c - 打开多个文件的大中央策略

audio - 优化显存和系统内存之间的传输

ios - NSKeyedArchiver 继承自 NSCoder 为什么会存在 NSKeyedUnarchiver?