【问题标题】:ARC: When to set a viewController to nilARC:何时将 viewController 设置为 nil
【发布时间】:2012-03-13 10:15:41
【问题描述】:

我仍然对 ARC 的想法有些挣扎。假设我有两个非常复杂的视图控制器 A 和 B,每个视图控制器中都有很多图片,每个视图都保留了这些图片。为了论证的缘故,我们假设第一个 ViewController (A) 保留了占用 75 MB RAM 的图像。另一个 (B) 也占用 75 MB。

在我的 App Delegate 中,我这样设置 NavigationController:

ViewControllerA *vcA = [[ViewControllerA alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:vcA];
[navController.navigationBar setHidden:YES];
[[self window] setRootViewController:navController];

当我从 A 切换到 B 时,我在 ViewControllerA.m 中这样做:

ViewControllerB *vcB = [[ViewControllerB alloc] init];
[[self navigationController] pushViewController:vcB animated:YES];

当我切换回来时,我会在 ViewControllerB.m 中这样做:

[[self navigationController] popToRootViewControllerAnimated:YES];

现在我最大的问题是,当我在 ViewController B 中时,我的内存中是否还有 ViewController A?在这种情况下,编译器什么时候释放一个 ViewController?我可以或应该在不使用时释放(即设置为零)一个 ViewController 吗?

如果答案很明确或者我完全没有抓住重点,我很抱歉。因此,任何答案和解释都将受到高度赞赏。

【问题讨论】:

    标签: iphone objective-c ios5 automatic-ref-counting


    【解决方案1】:

    是的,你仍然有 ViewControllerA(你可以在下次使用 Instruments 看到这个)。这与ARC无关,没有它也是如此。让我解释一下:

    您创建一个 UINavigationController 并将 UIViewController A 作为根,A 被保留(在 ARC 中它是一个强属性或类似的东西),您可以看到 UINavigationController 需要它,对吗? 现在你推送 UIViewController B,B 和 A 存在于内存中,你 UINavigationController 仍然需要 UIViewController A,它只是不显示并且可以卸载视图,如果系统需要内存,但它不会释放 A。当你弹出 UIViewController B ,它被释放,如果没有引用它(再次,我假设这就是 ARC 的工作方式)它被释放。

    现在您的问题是,rootViewController 何时解除分配?好吧,UINavigationController always 有根!所以,当你有一个 UINavigationController 你有一个 rootViewController。

    如果您需要进一步解释,请在 cmets 中告诉我。

    【讨论】:

      【解决方案2】:

      我无法帮助您使用 ARC,因为我从未使用过它(而且我不知道我是否真的想要)。

      但我可以告诉你一件事:

      当您推送 ViewController 时,它们都在导航堆栈中。在它们进入堆栈之前,它们一直保留在内存中。

      不使用 ARC,如果我自动释放我推送的eatch viewController,它将在我从堆栈中弹出它的时候被释放。

      如果有人了解更多关于 ARC(以及它何时释放分配的对象)的信息,我会很高兴了解更多信息。

      谢谢

      【讨论】:

        【解决方案3】:

        您的视图控制器 A 将由 navController 保留,因此不会被释放。即使您将vcA 设置为nil,它也不会被释放,因为navController 会保留它。 问题是您的控制器保留了占用大量内存的大量资源(图像)。为了解决这个问题,您可以在viewDidLoad 上分配资源并在viewDidUnload 上释放它们

        例如

        // in your view controller
        - (void)viewDidLoad {
            [super viewDidLoad];
            self.image = // read image to memory
        }
        
        - (void)viewDidUnload {
            [super viewDidUnload];
            self.image = nil; // release the image to free memory
        }
        

        然后在视图控制器 B 被推送到 navController 之后,视图控制器 A 将被 UIKit 通知它不是显示控制器,如果需要它会卸载视图以便释放内存供其他类使用。

        【讨论】:

        • 对不起,我认为你弄错了。 ViewDidLoad 和 ViewDidUnload 在视图创建时和视图被销毁之前(dealloc 之前)被调用。也许你想谈谈 viewWillAppear 和 viewWillDisappear 方法,它们被称为在 viewController 的视图显示/隐藏时进行。最后,这是我自己的观点,我认为如果图像加载一次会更好,特别是如果控制器的显示是经常的。
        • 如果您在每次出现/消失时分配和释放图像,那么每次视图更改都将是一个扩展操作,可能会导致应用程序滞后。 UIKit 知道何时卸载视图以节省不必要的加载/卸载工作。
        • 我完全同意你的看法。我想说的是,在 viewDidLoad/viewDidUnload 中分配/释放图像与在 initWithNibName/Dealloc 方法中没有区别。
        • 视图控制器可以多次借出/卸载其视图,但只有一次 init/dealloc,只有在需要比较加载 init 中的所有内容时,加载视图和其他资源才不同
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-15
        • 1970-01-01
        • 1970-01-01
        • 2012-07-11
        • 2020-05-12
        • 2017-05-20
        • 2013-04-27
        相关资源
        最近更新 更多