Addsubview和dealloc用于内存泄漏(retainCount)

时间:2012-06-14 07:26:19

标签: iphone memory-leaks release addsubview retaincount

添加到视图后,我检查子视图的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,工具栏的第一个日志retainCount是2,因为工具栏在init之后并添加到自我视图中,retaincount将变为2。

2,在工具栏removeFromSuperView之后,retainCount将变为1。

3,工具栏调用release方法后,retainCount仍为1,它不能变为0.在我的选项中,因为超级视图仍然是工具栏(自我视图不释放),所以工具栏可以不会减少到0。

4,如果调用工具栏设置为nil,则retainCount将为0.此日志无用。

我的问题是:

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

b)从apple文档中,子视图被添加到自我视图中,自我视图仍然是工具栏句柄,因此在dealloc方法中,如果未调用viewDidUnload,则工具栏retainCount不能减少为0如果内存不足,系统会减少无用的视图并调用viewDidUnload方法,它会自动将工具栏的retainCount减少为0.所以在dealloc方法中,我应该将工具栏设置为nil。如果我将工具栏设置为nil,我很困惑,当调用viewDidUnload方法时,工具栏会减少与否?有没有妈妈泄密?

THX。

1 个答案:

答案 0 :(得分:2)

首先,如果您的代码反映了您的真实代码,那么您的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;如果不存在,您的保留/释放呼叫会受损。这可以解释您是否需要首先在dealloc中调用release然后nil属性:

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

通过这样做,你发布toolbar两次;但由于在分配retain属性时没有使用autorelease,这将产生正确的结果。

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

正如我所说,您无需直接致电removeFromSuperView即可在dealloc时发布子视图,因为self.view会为您执行此操作。当您想要在保持superview的同时删除子视图时,这是另一回事(假设您显示标签然后将其删除);在这种情况下,你需要同时调用它们,否则你会有泄漏。

  b)从apple文档中,子视图被添加到自我视图中,自我视图仍然是工具栏句柄,因此在dealloc方法中,如果未调用viewDidUnload,则工具栏retainCount不能减少为0如果内存不足,系统会减少无用的视图并调用viewDidUnload方法,它会自动将工具栏的retainCount减少为0.所以在dealloc方法中,我应该将工具栏设置为nil。如果我将工具栏设置为nil,我很困惑,当调用viewDidUnload方法时,工具栏会减少与否?有没有妈妈泄密?

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

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