在我的非 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
不以alloc
或new
开头,也不包含单词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/