在非 ARC 代码中从 NSKeyedArchiver 中提取数据
Extracting Data from NSKeyedArchiver in Non-ARC Code
在我的非 ARC iOS 项目中,我有一个 returns 归档数据的方法:
- (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
。它不属于你。换句话说:你没有保留这个对象;你不能在上面调用 release。
然后您释放 archiver
,它负责 data
。 data
不再存在。解决方法是在发布之前保留它 archiver
:
NSData* data = [[archiver encodedData] retain];
这实际上与原始代码通过使用 +[NSMutableData alloc]
初始化 data
所做的相同。请注意“分配”一词。这将所有权(保留)赋予 data
.
根据相同的命名约定,此方法承诺 return 调用者不需要释放的对象。 (通常最容易将其视为净保留计数为 0,但在很多情况下并非如此。)
- (NSData*) archivedData { ... }
您在 data
上设置了保留,因此您需要对其进行平衡。但是,您希望该对象存活足够长的时间以便 returned。修复是 -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 中进行了总结。
在我的非 ARC iOS 项目中,我有一个 returns 归档数据的方法:
- (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
。它不属于你。换句话说:你没有保留这个对象;你不能在上面调用 release。
然后您释放 archiver
,它负责 data
。 data
不再存在。解决方法是在发布之前保留它 archiver
:
NSData* data = [[archiver encodedData] retain];
这实际上与原始代码通过使用 +[NSMutableData alloc]
初始化 data
所做的相同。请注意“分配”一词。这将所有权(保留)赋予 data
.
根据相同的命名约定,此方法承诺 return 调用者不需要释放的对象。 (通常最容易将其视为净保留计数为 0,但在很多情况下并非如此。)
- (NSData*) archivedData { ... }
您在 data
上设置了保留,因此您需要对其进行平衡。但是,您希望该对象存活足够长的时间以便 returned。修复是 -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 中进行了总结。