UINavigationController和UIViewController的dealloc函数

3

最近我将我的应用改为使用UINavigationController,之前我使用的是UINavigationBar并进行级联子视图添加,这有些不稳定。

我现在面临一个内存使用问题。Leaks工具没有显示任何泄漏,但是我创建并添加到UINavigationController中的ViewControllers似乎从未被释放。因此,每次我创建新的VC并按下NavigationController的返回按钮时,内存使用量都会增加。

我只是通过以下方式创建和添加我的VC:

DetailViewController* detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
// setups
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];

这个应用程序从未经过ViewController的deallocviewDidUnload方法。我每次按返回按钮时,这些方法都不应该被调用吗?

我已经搜索了很多教程并阅读了苹果的内存管理文档,但在使用NavigationController时,关于VC在内存中的生命周期没有任何说明。


Jukurrpa,你解决了这个问题吗?我也遇到了同样的问题,真的很困扰我。 - Wayne Lo
2个回答

5
也许你没有做错什么,而是遇到了像这个的问题。
在博客文章中,问题是我们是否需要手动释放IBOutlets。事实证明我们确实需要这样做。这在iOS 3.1.3中是可重现的,但我还没有在iOS 4.0中测试过。
第二种方法是重写视图控制器的保留和释放方法并打印出保留计数。我遇到了类似的问题,一些视图控制器的dealloc方法没有被调用,所以我重写了这些方法来查看是否有人仍然保留它。结果证明确实如此。
编辑:当我打印我的保留计数时,有时会达到约98个,这是由框架引起的,所以不用担心。
如果您的最后一个保留计数保持为2且dealloc方法不会被调用,则有人仍然保留它。
在这种情况下,您应该在其他地方搜索。
例如,在同一问题期间我遇到的另一个问题: 有时我会使用
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateUI) userInfo:nil repeats:YES]
来不断更新UI。但我忘记了NSTimer将保留目标对象(即ViewController)。因为NSTimer保留了您的视图控制器,所以您的dealloc永远不会被调用,因为有人(NSTimer)仍然保留它。因此,在dealloc方法之前,您必须确保使NSTimer无效以正确释放视图控制器。
编辑2:回应下面的评论,一个声明的保留属性的示例如下:
- (void)setTarget:(id)value {
  if (value != target) { 
    [target release];
    target = [value retain];
}

所以,它首先释放当前的self.target值,然后保留新值。由于你正在赋值为nil,因此你的目标在此之后将为nil。有关属性的更多信息可以在Apple文档中找到。


我确实在dealloc方法中释放了每个outlet。但是它没有任何效果,因为它从未被调用。我尝试重写release和retain,除了retainCount在某些时候达到50+(由子视图引起?)之外,最后一个release后它仍然保持为2(当我离开视图时)。我不知道为什么会这样,因为我只在我发布的代码中使用它。 - Jukurrpa
那帮助我修复了剩下的保留问题,谢谢。我没有使用NSTimer,但我使用了一个ASIHTTPRequest的包装器,其中DetailViewController作为某些操作的委托。当DetailVC viewDidDisappear被调用时,我只需要释放它。 也许最后的保留也是由于类似这样的原因,我会继续搜索。 - Jukurrpa
我刚刚通过在之前提到的包装器中释放后添加“self.target = nil”来修复了第二个剩余的保留问题(目标是DetailVC,存储为具有保留属性的id)。这可能是什么原因呢? - Jukurrpa
HTTPRequest听起来像是你正在使用某种异步操作?如果是这样,你应该知道当你在请求完成后调用目标选择器时,你的目标可能会被释放(可能是通过关闭视图),因此你的应用程序将崩溃,因为你正在调用已释放对象上的内容。 - Buju
是的,这是用于异步HTTP请求的。但是当我释放它时,所有请求都被取消了,所以它不会调用我的VC的选择器。您有关于self.target = nil的任何想法吗?尽管我之前做了[self.target release]。 - Jukurrpa
显示剩余3条评论

2
我也见过这种情况。正如你所指出的,我没有在文档中看到任何明确的说明,但我的观点是它们会一直保留在内存中,直到内存被需要为止。从性能角度来看,这是有意义的,因为这样可以使应用程序快速地在不同的视图之间切换。
总之,我不会担心这个问题。你可以在模拟器中触发一些“低内存警告”,看看它是否释放了你的VCs。

感谢您的回答。我刚刚在模拟器中创建并离开了大约10个VC之后尝试发送低内存警告。所有VC的viewDidUnload方法都被调用了,但是根本没有dealloc!而且根据它们在内存中的地址,似乎没有被重用,因此内存使用量不断增加。 - Jukurrpa
我建议您查看苹果开发者论坛。您可能会从苹果DTS主持人中找到更详细的答案。 - Jason McCreary
我从未在这个论坛上发过言,我可能会去看看,谢谢。 - Jukurrpa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接