【问题标题】:ViewWillDisappear versus deallocViewWillDisappear 与 dealloc
【发布时间】:2010-09-24 16:00:11
【问题描述】:

我在视图控制器的 dealloc 方法中放置了一个 NSlog。它不会被一致地调用。我确实注意到 ViewWillDisappear 总是被调用。将我所有整洁的upcode移到这里可以吗?将东西设置为 Nil 并释放调用。

有人对为什么不调用 dealloc 有一些建议吗?我知道它在文档中说它可能不会被调用,但如果你有一个非常简单的应用程序,它总是会被调用。所以我做的事情一定会影响dealloc。

这是调用我的 ViewController 的代码,而不是总是调用我的 dealloc。

-(IBAction) playComputerTapped:(id)sender
{

PlayGameViewController *pgvc = [[PlayGameViewController alloc] initWithNibName:@"PlayGameViewController" bundle:[NSBundle mainBundle]]; pgvc.gameMode = 1; [自我presentModalViewController:pgvc动画:是]; [pgvc 发布]; }

以上代码将我从邮件菜单 ViewController 带入游戏。

下面是离开 gameViewController 并带我回到菜单的代码。

[self.parentViewController dismissModalViewControllerAnimated:YES];

谢谢 -代码

【问题讨论】:

    标签: iphone objective-c


    【解决方案1】:

    你不是说viewDidUnload 而不是viewWillDisappear 吗?

    viewWillDisappear 在视图控制器消失时被调用。这通常发生在视图控制器被弹出或其他视图控制器被推送到堆栈时。 viewWillDisappear 的目的是停止活动动作 - 例如停止动画、隐藏某些元素或类似的。

    viewDidUnload 可能是您的意思,因为在卸载视图控制器的视图时会调用它。对于当前可见的视图控制器,这绝不应该发生,仅适用于导航堆栈中某处(UITabBarController 或 UINavigationController 的一部分)但当前不可见的控制器。 viewDidUnload 的目的是释放作为视图一部分且视图控制器也保留的任何 UI 元素。

    要了解为什么要卸载此类控制器的视图的原因,这一点很重要。原因是内存消耗。视图会消耗大量内存,即使它们当前不可见。视图通常很容易重构——只需调用最初构建它们的代码即可。如果您使用 Interface Builder,这尤其容易。因此,这些视图是释放以获得更多内存的最佳候选。

    当系统没有足够的内存时,它开始调用当前不可见的视图控制器的didReceiveMemoryWarning 方法。如果您在 Xcode 中从模板创建了控制器,则此方法只需调用 super 的 (UIViewControllers) 实现 [super didReceiveMemoryWarning]。该默认实现将释放self.view,而后者又应将其连同其所有子视图一起释放。

    现在假设您的视图控制器需要访问某些子视图才能以某种方式对其进行操作。例如,您可以在那里有一个 UILabel 元素,并且您希望相应地更改其内容。要访问此元素,您需要创建一个成员变量 (IBOutlet) 并将其连接到该元素。现在您的视图控制器拥有该标签,因此它的保留计数增加了。当控制器的视图被释放时,标签也会被释放,但是因为您的视图控制器仍然保留标签,所以它不会被释放。因此,您应该在viewDidUnload 方法中释放标签。

    我见过以编程方式创建视图的应用程序(在loadView 方法中),但加载是以一种肮脏的方式完成的,以至于一旦释放视图就无法重建视图。因此,每次系统内存不足时,它都会调用didReceiveMemoryWarning,后者又会释放视图,但在导航回该视图控制器应用程序后崩溃了。一个快速的“错误修复”是删除视图控制器中的 [super didReceiveMemoryWarning] 调用。好吧,系统没有得到内存,出现了一些奇怪的效果,但至少应用程序没有立即崩溃。

    现在是第三个 - dealloc。当对象不被任何人拥有并且它的内存将被释放时调用它。在这里,您需要释放您保留的所有对象。对于视图控制器,这些通常是对模型类的引用。

    我想描述另一种可能的情况。假设您有一个显示与另一个人聊天的视图控制器。假设这是非常花哨的聊天,带有动画的表情符号和好友图标。假设每个聊天条目都显示为 UITableView 的一个单元格。

    当您的好友向您发送消息时,您希望通过重新加载将新单元格附加到表格视图中。因此,您的视图控制器有一个到表视图的出口。

    viewWillDisappear 你应该停止表情和图标的动画。 在viewDidUnload 中,您应该释放表格视图。 在dealloc 中,您想发布聊天历史记录(可能是在此对话期间发送和接收的所有消息的 NSArray)。

    现在,如果您离开聊天,viewWillDisappear 会被调用并停止动画。

    当系统内存不足,并且您的视图控制器不可见时,didReceiveMemoryWarning 被调用并释放视图。你的viewDidUnload 被调用并释放 UITableView 以便它可以真正被释放。

    当您导航回聊天时,loadView 再次被调用,您的视图再次被构建,viewDidLoad 之后被调用。您的模型(聊天对话的表示)仍然存在,因此 table-view 的数据源具有与以前一样的所有数据,因此 table-view 将显示与视图被释放之前完全相同的内容。毕竟viewWill/DidAppear 是在你开始动画的地方调用的。

    当你和你的朋友聊天结束时,你释放视图控制器,它被释放 - dealloc 被调用,你释放一个包含聊天消息的数组,并清理其他所有内容。

    我希望它能让事情变得更清楚。

    【讨论】:

    • 所以我应该在每个UIViewController 中释放我在viewDidUnload 中的所有 网点?
    【解决方案2】:

    这取决于。

    如果您需要减少应用程序的内存占用,则在视图不可见时通过viewWillDisappear 卸载内容是一个不错的方法。但是,一旦再次显示视图,您将需要重新初始化所有内容,这取决于其内容,这可能会产生相当大的开销 - 甚至可能不需要。

    对于小型应用程序(就内存使用而言),使用 dealloc 来卸载你的东西很好。仅当对象保留计数降至零时才会调用它,并且是在对象被销毁之前运行的最后一个方法。使用 autorelease 时,情况可能不会马上出现,当然对象可能会被 parentviewcontroller 以外的其他对象保留,从而防止它被销毁,从而避免调用 dealloc。

    您可能想查看Memory Management Programming Guide,它会更详细地解释事情。

    【讨论】:

    • 我正在使用这种方法,这是因为我想积极主动。我不想等待,希望 iPhone 在内存不足时能做正确的事情。另外,当内存非常低时,iPhone 只会关闭内存使用率最高的应用程序。我不想成为那个应用程序。在我看来,这是谨慎的
    猜你喜欢
    • 1970-01-01
    • 2014-04-13
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多