为啥在 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?的主要内容,如果未能解决你的问题,请参考以下文章
Objective-c:为啥在使用 KVC 时私有 ivars 不被外部访问隐藏
为啥在我的自定义 UIView 类中没有调用 init(frame: CGRect)?