我试图了解引用计数是如何工作的,所以我禁用了ARC并编写了一个简单的类:( Foo.h未粘贴,因为它未被修改)
@implementation Foo
- (instancetype)init
{
NSLog(@"Init object");
return [super init];
}
- (void)dealloc
{
NSLog(@"Dealloc object");
[super dealloc];
}
@end
#import <Foundation/Foundation.h>
#import "Foo.h"
int main(int argc, const char * argv[]) {
Foo *obj = [[Foo alloc] init];
obj = nil;
return 0;
}
现在我希望看到dealloc object
日志,因为对Foo
对象的唯一引用已经消失,但我收到的唯一消息是init object
。
为什么我不明白?当我分配obj = nil
?
答案 0 :(得分:5)
没有。如果您不使用ARC,则在致电[obj release];
时会释放该对象。 (ARC为您插入这些调用。)将obj
设置为nil
在内存管理方面没有任何作用(尽管它确实创建了一个您无法再访问的对象!)。
基本上,在没有ARC的Cocoa中:
[obj retain]
。 (alloc
为你做这件事。)[obj release]
。当对象的保留计数达到0时,release
依次调用dealloc
。[obj autorelease]
。最常见的情况是,当您从方法返回一个对象时(并且不想保留对它的所有权),会发生这种情况。答案 1 :(得分:1)
另外一些观察要扩展mipadi的优秀答案:
在非ARC代码中,将变量设置为nil
将不释放该对象。您必须明确release
/ autorelease
它。
更准确地说,如果所有权已转移给您(即您从名称以alloc
,new
,copy
开头的方法获取对象,或者mutableCopy
),然后您负责明确调用release
/ autorelease
。
底线,只是将变量设置为nil
是不够的。
我因为担心这个问题蒙上阴影而犹豫不决,但在处理属性时,它有点不同。使用属性,调用retain
属性的setter将自动retain
对象为您。如果您稍后将属性设置为nil
,则设置者将自动release
为您提供。
想象一下这样的课程:
@interface Bar : NSObject
@property (nonatomic, retain) Foo *foo;
@end
如果要设置foo属性,可以执行以下操作
Foo *f = [[Foo alloc] init]; // create Foo object with +1 retain count
self.foo = f; // the `retain` property will increase retain count to +2
[f release]; // resolve the local strong reference, reducing retain count back to +1
或者更简单:
self.foo = [[[Foo alloc] init] autorelease];
这样做会创建一个具有+1保留计数的Foo
对象。通过设置foo
属性,您将创建另一个strong
引用,从而最终得到+2保留计数。然后,当您release
/ autorelease
时,保留计数会回落到+1。
稍后,当您完成foo
并想要发布它时,您只需再次调用setter,这次使用nil
值:
self.foo = nil; // resolve the `retain` done by the property, reducing the retain count to +0
这减轻了对foo
属性维护的强大参考。您不自己致电release
(至少在酒店上)。显然,当您使用nil
值调用setter时,不仅会释放上一个对象,但如果这是最后一个强引用,那么该对象也将被释放。
简而言之,原始alloc
被release
/ autorelease
偏移,而不是将变量设置为nil
。但是,通过将该属性设置为retain
来解析nil
属性的设置。
最后几点意见。
我建议如果编写非ARC代码,请仔细查看高级内存管理编程指南,,特别是Memory Management Policy章。
Xcode的静态分析器( shift + 命令 + B ,或&#34;分析&#34;在Xcode&#34;产品&#34;菜单上)非常适合识别困扰非ARC代码的内存问题。始终确保静态分析仪绝对没有警告。
使用Instruments时,分配工具有一个名为&#34;记录参考计数&#34; (见https://stackoverflow.com/a/14105056/1271826)。如果您发现某个对象未被释放,则此工具可用于诊断对象的整个生命周期,并且所有对象都可以保留计数。