0

添加到视图后,我正在检查子视图的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、工具栏调用释放方法后,retainCount还是1,不能变成0。在我的选项中,因为超级视图是保留工具栏(自身视图不释放),所以工具栏不能重用0。

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

我的问题是:

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

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

谢谢。

4

1 回答 1

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; 如果它不存在,则您的保留/释放调用会受到损害。这可以解释您需要先调用release然后nil在 dealloc 中的属性:

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

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

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

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

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

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

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

于 2012-06-14T07:57:06.837 回答