UINavigationController:弹出时释放 ViewController 的内存

Posted

技术标签:

【中文标题】UINavigationController:弹出时释放 ViewController 的内存【英文标题】:UINavigationController: Release ViewController's memory when popped 【发布时间】:2011-10-19 20:29:51 【问题描述】:

我在 SO 上看到过一些关于这个主题的帖子,但没有明确的答案。这是我的问题。

我有一个UINavigationController 用作画廊。在第一个控制器上,我加载了一堆远程图像。这会增加我的内存大小,但不会增加那么多。单击图像时,它将推送另一个viewController,其中包含刚刚单击的图库的图像。这可能会从这些图像中加载另外 1MB 或更多的数据。

这里的问题是用户可能浏览任意数量的这些画廊。因为当我弹出 viewController 时,内存没有释放,当用户继续浏览画廊时,我的应用程序开始使用过多的内存。

当我弹出我的viewController 时,有什么方法可以释放这个内存?也许在我的viewDidDisappear: 方法中?如果是这样,我会释放什么?我怎样才能再次创建它?我尝试了这一点,例如释放我的视图,但我遇到了崩溃。

对此问题有任何见解吗?

PhotosGalleryiPad *gallery = [[PhotosGalleryiPad alloc] init];
gallery.items = self.items;
gallery.asset = self.currentAsset;
[self.navigationController pushViewController:gallery animated:YES];
[gallery release];

【问题讨论】:

老实说...听起来内存真的应该在您从堆栈中弹出时加载的视图的“dealloc”中卸载。您确定要正确释放 dealloc 中的所有照片数据吗?除非您以某种方式允许用户在不单击“返回”按钮的情况下无休止地向前导航一堆视图...视图导航器中的视图通常应该在单击标题中的返回按钮时解除分配。如果是这种情况,那么您可能需要查看不同的导航范例。 不,dealloc 被调用并且我的属性正在被释放。他们只需单击,推动控制器,然后单击正常的“返回”按钮即可弹回根目录。 【参考方案1】:

您通常会在视图控制器的 dealloc 方法中释放从堆栈中弹出的所有内存。

但是,如果您正在谈论图像并且使用[UIImage imageNamed:] 加载它们,那么 UIKit 可能会缓存它们。尝试在模拟器中伪造内存警告(从硬件菜单中),看看是否会卸载这些缓存的图像。

您还可以在 Instruments 中进行 heapshot 分析。在加载视图控制器之前标记堆,在关闭视图控制器后再次标记它,看看哪些对象仍然存在。

【讨论】:

【参考方案2】:

您将这些画廊图片保留在哪里?

让我猜猜gallery.items 是一个保存图像的可变集合(可能是一个数组)。当用户访问新的画廊时,更多的图像被添加到这个数组中。从视图控制器到视图控制器,您正在传递一个指向该数组的指针:

gallery.items = self.items;

因此,当您弹出视图控制器时,您仍然会留下相同的放大数组。那么问题来了,当你弹出一个视图控制器时,如何剔除这个新添加的图像数组。

您可以创建一个shallow copy of the collection,而不是传递一个指针。如果它是一个可变数组,你可以这样做:

gallery.items = [self.items mutableCopyWithZone:nil];

然后,当一个视图控制器被弹出时,它的items 数组被释放。弹出的视图控制器添加的对象被释放,但旧的对象仍然保留在前一个视图控制器的items数组中。

(我只是在猜测。如果我错了,如果你能解释一下你在哪里保留这些图像会很有帮助。)

【讨论】:

不,它不是图像数组。它是一个图像 URL 数组,只是 NSStrings。我需要做一些研究,我感觉这可能是由我使用的一些第三方代码引起的。 听起来不像是保留图像的视图控制器。如果您在 dealloc 中适当地释放属性,我能想到视图控制器保留任何内容的唯一方法是通过不被复制的集合。也许如果您查看图像的创建或下载位置,您会发现它们的存在。【参考方案3】:

如果您像这样将视图“弹出”到前景:

infoScreen = [[[infoScreen alloc] initWithNibName:@"InfoScreen" bundle:nil] autorelease];
infoScreen.view.center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2);
[self.view sendSubviewToBack:self.view];

那么你会做[infoScreen release]; 从内存中释放/释放视图。 记住你allocretain 的任何事情(还有其他情况,但我暂时忘记了)你需要release

【讨论】:

我了解内存管理规则。我不确定我是否在这里遵循您的建议。 也许我误解了你的问题,我认为你需要帮助从不再使用的视图控制器中释放内存。 是的,当我将视图控制器从堆栈中弹出时,它似乎保留了内存。

以上是关于UINavigationController:弹出时释放 ViewController 的内存的主要内容,如果未能解决你的问题,请参考以下文章

UINavigationController 作为 iPhone 上的弹出框?

UINavigationController:弹出时释放 ViewController 的内存

当我触摸后退按钮时,为啥 UINavigationController 不弹出 UITableViewController?

UINavigationController 没有在 iPad 上弹出 UINavigationBar 项目

从 UINavigationController 弹出视图会改变设备方向

弹出 UINavigationController 时崩溃