【问题标题】:Addsubview and dealloc for memory leaks (retainCount)内存泄漏的 Addsubview 和 dealloc (retainCount)
【发布时间】:2012-06-17 05:10:19
【问题描述】:

添加到视图后,我正在检查子视图的 retainCount。代码是:

- (void) loadView{
    //...
    toolbar = [[UIToolbar alloc] initWithFrame:nil];
    [[self view] addSubView:toolbar];
}

- (void) dealloc{
    NSLog(@"count=%d", [toolbar retainCount]);   // count=2
    [toolbar removeFromSuperView];
    NSLog(@"count=%d", [toolbar retainCount]);   // count=1
    [toolbar release]
    NSLog(@"count=%d", [toolbar retainCount]);   // count=1
    toolbar = nil;
    NSLog(@"count=%d", [toolbar retainCount]);   // count=0
}

从dealloc{}中的这段代码,我有一些问题:

1,toolbar的第一个日志retainCount是2,因为toolbar在init之后添加到self view,retaincount会变成2。

2、工具栏removeFromSuperView后retainCount变为1。

3、toolbar调用release方法后retainCount还是1,不能变成0不归零。

4,如果调用工具栏设置为nil,retainCount将为0。这个日志没用。

我的问题是:

a) 工具栏调用 removeFromSuperView 和发布 API,结果是一样的,工具栏的 retainCount 只会变成 1。所以如果我测试代码只使用它们中的每一个,结果是一样的。那么,我可以断定用户只能调用每一个 API 就可以了吗?

b)从苹果文档中,子视图添加到自身视图中,自身视图保留了工具栏句柄,所以在dealloc方法中,如果没有调用viewDidUnload,工具栏retainCount不能减为0 . 如果内存不足,系统会减少无用视图并调用viewDidUnload方法,它会自动将工具栏retainCount减少为0。所以在dealloc方法中,我应该将工具栏设置为nil。如果我将工具栏设置为 nil,我很困惑,当调用 viewDidUnload 方法时,工具栏是否会缩小?有没有内存泄漏?

谢谢。

【问题讨论】:

  • 但是对于子视图内存,当子视图释放释放时,应该只调用内存不足的viewDidUnload方法吗?
  • 在仪器中测试内存泄漏。像这样检查保留计数不会告诉你任何事情。
  • 你永远不应该使用retainCountstackoverflow.com/questions/11028512/…
  • 我有一些内存问题,使用 Instruments Allocations 来检查内存,内存会慢慢增加。
  • 您能否提供toolbar 属性的声明?它是保留/强还是弱/分配?你在使用 ARC 吗?

标签: iphone memory-leaks release addsubview retaincount


【解决方案1】:

首先,如果您的代码反映了您的真实代码,那么您的 dealloc 方法就有一个大问题:

- (void) dealloc{
   [toolbar removeFromSuperView];
   [toolbar release]
   toolbar = nil;
}

你没有打电话给[super dealloc]。通过不调用 [super dealloc],self.view 将永远不会被释放(并最终被释放)。

这应该可以解决您的内存泄漏问题(至少部分解决):

- (void) dealloc{
    [toolbar release];
    [super dealloc];
}

您可以注意到我已经删除了对removeFromSuperView 的调用,因为当self.view 实际被释放时,这会自动为您完成,所以您不需要自己做。无论如何,调用removeFromSuperView 也不会造成任何问题。

关于您的问题,我假设您的 toolbar 属性声明为 retain(根据您提交的代码,这对我来说是最合理的假设)。

如果toolbarretain 属性的孩子,那么为它分配新创建的视图的正确方法是:

 toolbar = [[[UIToolbar alloc] initWithFrame:nil] autorelease];

请注意autorelease;如果它不存在,则您的保留/释放调用会受到损害。这可以解释您需要先调用release,然后调用nil dealloc 中的属性:

- (void)dealloc {
 ...
    [toolbar release]
    toolbar = nil;
 ....
}

通过这样做,您将释放toolbar 两次;但是由于您在分配给保留属性时没有使用autorelease,这将产生正确的结果。

a) 工具栏调用 removeFromSuperView 和发布 API,结果是一样的,工具栏的 retainCount 只会变成 1。所以如果我测试代码只使用它们中的每一个,结果是一样的。那么,我可以断定用户只能调用每一个 API 就可以了吗?

正如我所说,您无需直接调用removeFromSuperView 即可在dealloc 时间发布子视图,因为self.view 将为您完成此操作。当您想要删除子视图同时仍保留superview 时(假设您显示一个标签然后将其删除),这是另一回事;在这种情况下,您需要同时调用两者,否则您有泄漏。

b)从苹果文档中,子视图添加到自身视图中,自身视图保留了工具栏句柄,所以在dealloc方法中,如果没有调用viewDidUnload,工具栏retainCount不能减为0 . 如果内存不足,系统会减少无用视图并调用viewDidUnload方法,它会自动将工具栏retainCount减少为0。所以在dealloc方法中,我应该将工具栏设置为nil。如果我将工具栏设置为 nil,我很困惑,当调用 viewDidUnload 方法时,工具栏是否会缩小?有没有内存泄漏?

如果我正确理解您的疑问,那么重点是如果您将toolbar 属性发送到viewDidUnload 中的nil,那么当调用此方法时(当您显式删除视图或内存警告时)已发布)您的子视图已正确处理;如果以后调用您的控制器的dealloc,则您的属性已经具有nil 值,因此释放它不会有任何效果(但这很好,因为它已经在viewDidUnload 中发布了)。

另一方面,如果您不释放viewDidUnload 中的属性,那么如果在内存警告后再次显示视图,则会再次调用loadView/viewDidLoad;但是在这种情况下,当您创建工具栏子视图并将其引用分配给toolbar 属性(假设它是retain 类型)时,旧对象会自动为您释放,因此您不会有任何内存泄漏;发生的情况是您使用了更多可能的内存(因为直到再次创建 self.view 时工具栏才被释放)。

【讨论】:

  • 对不起,我忘了排队。
  • 你忘记了:“retainCount 没用。不要调用它。”
猜你喜欢
  • 1970-01-01
  • 2011-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 2013-11-08
  • 2016-05-03
相关资源
最近更新 更多