为啥在 init 方法中为 iVar 定义调用 autorelease?

Posted

技术标签:

【中文标题】为啥在 init 方法中为 iVar 定义调用 autorelease?【英文标题】:Why call autorelease for iVar definition in init method?为什么在 init 方法中为 iVar 定义调用 autorelease? 【发布时间】:2010-04-30 09:22:19 【问题描述】:

我刚刚熟悉了 CLLocationManager,发现了几个包含以下 init 方法的示例类定义:

- (id) init 
    self = [super init];

    if (self != nil) 
        self.locationManager = [[[CLLocationManager alloc] init] autorelease];
        self.locationManager.delegate = self;
    
    return self;


- (void)dealloc 
    [self.locationManager release];
    [super dealloc];

我不明白为什么 iVar 会自动发布。这不是说在init方法结束时就被释放了吗?

看到同样的示例代码在dealloc方法中有iVar释放,我也很疑惑。

有什么想法吗? '

【问题讨论】:

【参考方案1】:

locationManager 是一个可能使用retain 属性设置的属性。

基本上,如果你只写:

self.locationManager = [[CLLocationManager alloc] init];

左侧的self.locationManager 设置器保留对分配的CLLocationManager 的引用。但是右侧的CLLocationManager 引用本身从未发布过。此管理器的保留计数永远不会达到零,并且对象永远不会消失 - 这会导致内存泄漏。

有两种方法可以解决这个问题。 autorelease 分配的对象,正如您在引用的代码 sn-p 中看到的那样 - 或者您将分配的对象分配给临时变量,将临时变量保留到 locationManager 属性,然后显式释放临时变量:

CLLocationManager *_temporaryReference = [[CLLocationManager alloc] init];
self.locationManager = _temporaryReference; // this is retained
[_temporaryReference release];

就内存管理而言,这两种方法是等效的。有些人更喜欢第二种方法,因为他们不喜欢等待自动释放池被“清空”,尤其是在像 iPhone 这样的低内存设备上,这样可以更严格地控​​制对象的生命周期。

Apple 的 Objective-C Programming Language 文档更详细地解释了此属性。

【讨论】:

嗨,Alex,你又一次解除了我的困惑。非常感谢【参考方案2】:

还有一个没有临时变量或自动释放的替代方案:

locationManager = [[CLLocationManager alloc] init];

如果不使用self.locationManager,则不会为该变量调用类的setter 方法,因此不会将保留计数增加到2。编译器会将这些分配更改为[self setLocationManager: locationManager];。这假设您已将变量原型化为保留。

如果它是一个类变量(它是),你可以进行赋值。这是否是良好的编码实践值得商榷,但在我看来,这取决于它在课堂开始时的位置。

【讨论】:

【参考方案3】:

如果您的 self.locationManager 是一个保留它的属性,那么它会设置保留。通过执行 alloc,您确实将保留计数设置为 +1,这意味着到函数结束时它是 +2。当您说自动释放时,它将是 +1(因为保留属性)。您也可以在将其设置为属性后显式释放它,但是您所做的代码更少且易于阅读。

【讨论】:

这是误导。自动释放不会更改保留计数。它所做的只是将对象添加到自动释放池中,当池耗尽时,它将向对象发送释放。无论如何,最好不要考虑保留计数。只考虑所有权。该对象是使用 alloc 方法获得的,因此您拥有该对象。因此,您必须释放它或自动释放它以在您完成它时放弃所有权。可以安全地留下该财产来解决它自己的所有权问题。 感谢两位的澄清。我认为这很清楚,并且为 Jeremy 的保留计数课程感到高兴,因为这一切都归结为...... 杰里米的评论很重要。 “自动释放池”可能应该被称为“自动释放列表”,因为人们经常看到“池”这个词并错误地认为它类似于堆或实际包含对象的内存区域。自动释放只是一种延迟消息传递工具。

以上是关于为啥在 init 方法中为 iVar 定义调用 autorelease?的主要内容,如果未能解决你的问题,请参考以下文章

__init__ 为啥python类需要初始化

Objective-c:为啥在使用 KVC 时私有 ivars 不被外部访问隐藏

为啥在我的自定义 UIView 类中没有调用 init(frame: CGRect)?

ivars 和循环方法

为啥我的 ivar 没有在 NSManagedObject 子类上设置

为啥 Python 在创建实例时不调用实例方法 __init__() 而是调用类提供的 __init__() ?