从内存中分割和清除历史ViewControllers

时间:2013-01-01 09:43:55

标签: ios memory-management uiviewcontroller segue

我有一个iPad应用程序,它有很多屏幕和很多segue选项。 目前,我只是使用performSegueWithIdentifier来启动这些segue,我担心的是,当用户执行越来越多的segues时,我占用了大量内存。 我见过人们推荐使用函数popToRootViewControllerAnimated:如果使用UINavigationController,但问题是我没有使用它。 如何阻止VC的数量激增? 应用程序的工作方式,用户不断返回到根VC - 实际上是一个搜索屏幕。因此,如果我需要在需要这样一个segue时清除VC的堆栈,那我认为这将解决我的问题,但我不知道如何解决这个问题。 感谢您的任何建议。

4 个答案:

答案 0 :(得分:10)

当您使用segues时,流程会向后和向前移动。当用户向后移动(即按下“后退”)时,它将不会推送到新的VC,但它将弹出到已存在的VC。弹出时,当前VC将从堆栈和内存中删除。

如果你在流程中有向后移动的segues,那么这是错误的。你只需要segues继续前进。

正确的SEGUE准备

在准备segue时,你永远不应该创建自己的视图控制器并推送它们。故事板可以为您完成所有这些。

正确的prepareForSegue方法看起来应该是这样的......

- (void)prepareForSegue:(UIStoryBoardSegue*)segue
{
    if([segue.identifier isEqualToString:"SomeSegue"])
    {
        MyNewViewController *controller = segue.destinationViewController;

        controller.someProperty = "some value to pass in";
    }
}

这就是你所需要的一切。请注意,如果您打算将某些信息传递给新的视图控制器,则只需要此选项。如果你没有向前传递任何东西,那么你根本就不需要这种方法。

当方法结束时,新的VC将被故事板文件推送到屏幕上。

UNWIND SEGUES

如果您有随机流(如评论中所示),那么您可以使用展开segues来实现此目的。

在你'A'视图控制器中有一个类似......的功能

- (IBAction)someUnwindAction:(UIStoryboardSegue*)sender
{
    //some action to run when unwinding.
}

它需要接收UIStoryboardSegue对象。如果设置为IBAction,您也可以从Interface Builder访问它。

现在,当你想要去A> B> C> B>然后只使用了标准的推送和弹出(来自segue和后退按钮)。

当你想要去A> B> C>那么你可以使用来自控制器C的展开segue。

如果你有一个取消按钮或控制器C中的某个东西,这是在界面生成器中,这应该会带你回到控制器A.然后在控制器C下面的界面生成器中,你将有一个带有门的绿色小方块指出它的箭头。只需将取消按钮的操作指向此符号,然后选择“someUnwindAction”即可。 (注意,unwindAction在A中,按钮在C中。)然后XCode使用它来弹回你一直回到A并处理删除任何内存和东西。如果您愿意,也可以将其他信息发回给A.

如果您想以编程方式从C访问此展开segue,那么您可以运行...

[self performSegueWithIdentifier:"someUnwindAction" sender:nil];

这也将弹回A。

答案 1 :(得分:1)

imho我没有看到使用segue的任何问题,它比其他任何事情都简单得多。如果您担心消耗的内存,那么只需分析您的应用程序,看看它吃多少以及调用“内存压力处理程序”的频率。

答案 2 :(得分:0)

好的,我相信我已经弄明白了。它似乎有用。

由于我一直回到常见的VC,我将代码放在我想要回到这个'root'VC的地方以清除VC堆栈。

我仍在我的普通代码中执行实际的segue

[self performSegueWithIdentifier:@"editBackToSearch" sender:self]; 

然而,在'prepareForSegue:'方法中,我不再创建新的VC对象,而是执行任何我未完成的工作(保存我的数据),然后使用以下代码清除VC堆栈。

UIViewController *vc = self;
while ([vc presentingViewController] != NULL)
{
    vc = [vc presentingViewController];
}   
[vc dismissViewControllerAnimated:NO completion:nil];

它似乎运行顺畅,并具有释放这些VC吸收的内存所需的影响(通过分析器确认)。

最后一条评论 - 出于某种原因,我无法为解雇命令设置动画,这似乎触发了无限循环并导致了EXC_BAD_ACCESS。将动画设置为NO,虽然效果很好。

感谢您的帮助。

答案 3 :(得分:0)

Swift 3 :这是为了防止Swift 3和4中的内存泄漏

@IBAction func entryViewSelected(_ sender: UIButton) {

    self.dismiss(animated: true, completion: nil)
}