【问题标题】:Object leak using "retain"使用“保留”的对象泄漏
【发布时间】:2011-02-23 23:19:10
【问题描述】:

我有一个用我正在合成的保留属性定义的属性:

@property (nonatomic, retain) UISwitch *mySwitch;

在我的 loadView 中,我正在这样做:

self.mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 40, 20)];

最后在我的 dealloc 中我正在这样做:

self.mySwitch = nil;

由于我使用了一个分配器,我是否泄漏了这个对象 (mySwitch)?我应该在分配框架时自动释放它吗?

请提出建议。

【问题讨论】:

    标签: iphone cocoa-touch ios retaincount


    【解决方案1】:

    行:

    self.mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 40, 20)];
    

    实际上调用了 retain 两次- 一次用于 alloc 并再次分配给 self.mySwitch(这是您指定的属性,应该 retain 分配给它的任何值。)我被告知最好的解决方法是在线上添加对autorelease的调用,使其成为:

    self.mySwitch = [[[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 40, 20)] autorelease];
    

    【讨论】:

      【解决方案2】:

      是的,你在泄漏。您正在使用+alloc/-initWithFrame: 创建一个拥有的对象,然后将该拥有的对象分配给标记为retain 的属性。这将创建对该对象的第二个拥有的引用。此时,您泄漏了原始拥有的引用,这会导致对象本身泄漏。

      这里的正确行为是在将对象分配给属性之前调用-autorelease

      self.mySwitch = [[[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 40, 20)] autorelease];
      

      顺便说一句,不建议您访问-dealloc 内的属性。通常为此给出的两个原因是 1)这将广播 KVO 通知,您不希望在 -dealloc 内部,以及 2)如果有人覆盖设置器(在此类或子类中),它可能无法正常运行。推荐的方法是简单地释放底层 ivar,因此您会看到类似以下内容:

      [mySwitch release];
      

      将 nil 分配给该属性在其他任何地方都非常安全(并且推荐)。

      【讨论】:

      • 我在-dealloc 中看到了使某些属性无效的值。这样,您可以对属性对象释放顺序进行细粒度控制。顺便说一句,您只能减去我一次,但这并不能否定您使用非常危险的假设进行编程的事实。
      • 您是否使用属性与您发布 ivars 的顺序完全没有关系。
      • @Kevin 让我问你,如果你不覆盖-dealloc,你的属性将按什么顺序被释放。在你想出答案之后,想象一下你有一种情况,其中属性 B 将引用属性 A。在 B 之前收集 A 是非常危险的,尤其是当这些属性可以从不同的线程访问时。你获得了非法的内存访问。
      • 如果你的dealloc 的实现中有release 订单依赖项,你做错了。如果您的 dealloc 方法中存在线程依赖关系,则您做错了
      • @bioffe 我看不出这有什么关系。没有人声称 Apple 的框架是完美的,并且 that 听起来像是我所指的类型的排序依赖项。如果你在你的 dealloc 方法中有排序依赖,或者更糟糕的是,线程依赖,那么你做错了(是的,框架中存在问题可以归结为 - 并且,通过错误报告,它们已经固定)。
      【解决方案3】:

      作为自动释放的替代方案,如果您需要更严格的内存管理,这应该适合您:

      UISwitch *myswitch_tmp= [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 40, 20)];
      self.mySwitch = myswitch_tmp;
      [myswitch_tmp release];
      

      以及后来的例如在交易中

      [mySwitch release];
      

      【讨论】:

      • +1 因为是唯一一个不使用autorelease 的人。 autorelease 有一个地方,比如当你无法控制什么时候会保留一个对象(比如从方法中返回对象),但这里不是这样。
      • @Abizern:使用release 代替autorelease 是合理的,但大多数情况下它对应用程序的影响为零,同时使代码更难阅读和增加了程序员出错的风险(即最后忘记了release)。此外,虽然这不是很常见,但如果您的代码可以引发异常,并且异常将在堆栈中的更高位置被捕获(例如,它不会终止应用程序),release 将被跳过并且您会泄漏,但是autorelease 会起作用。
      • @Kevin Ballard - 在 NSCoderNight 上进行了 IRL 聊天。那是共识。即我只是很挑剔,这是一个过早的优化。但是关于 SO 的这么多答案似乎只是在不涉及一些相关问题的情况下提出“这就是你的做法”。不使用autorelease 是一种选择。选择使用哪个选项取决于开发人员,但至少这是一个明智的选择,而不仅仅是模仿一种编写代码的方式。
      【解决方案4】:

      是的。您正在泄漏对象。在这里记住一个简单的规则:

      如果您使用+alloc,则始终必须有对应的-release

      【讨论】:

      • 不,没有。应该有平衡的保留和释放计数。
      • @Kevin Ballard 我的意思是-release。感谢您指出。
      • 你的规则还是太简单了。除了+alloc,还有更多的方法可以获得拥有的关系。一个常见的首字母缩写词是 NARC - 这代表 newallocretaincopy(或 mutableCopy)。如果您调用这些方法中的任何一个,那么您最终会得到一个拥有的引用,并且必须调用 releaseautorelease 来摆脱该拥有的引用。
      • @bioffe 如果我的理解正确,您的意思是,尽管内存管理指南极其简单明了,但应该始终假设其他人的代码不会遵循这些指导方针,因此一个人应该……什么,在你前进的过程中制定规则?一旦你假设没有其他人遵循这些指导方针,你唯一的办法就是永远不要释放任何东西,因为担心它会崩溃,这会导致泄漏所有创建的对象。
      • @bioffe:因为它根本不正确。这里的假设是您正在对继承自 NSObject 或 NSProxy 的对象进行操作(如果不是,那么整个对话就没有实际意义,因为谁知道 dealloc 在其他对象上的含义?)鉴于此,手动调用 -dealloc绝对不正确。即使您使用自定义分配器,调用-dealloc 也是错误的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-02
      • 1970-01-01
      • 2013-02-09
      • 2011-11-14
      • 1970-01-01
      • 2012-12-06
      • 1970-01-01
      相关资源
      最近更新 更多