Segues 和从内存中清除历史 ViewControllers

Posted

技术标签:

【中文标题】Segues 和从内存中清除历史 ViewControllers【英文标题】:Segues and clearing historical ViewControllers from memory 【发布时间】:2013-01-01 09:43:54 【问题描述】:

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

【问题讨论】:

【参考方案1】:

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

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

为 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 来实现这一点。

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

- (IBAction)someUnwindAction:(UIStoryboardSegue*)sender

    //some action to run when unwinding.

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

现在当你想去 A > B > C > B > A 时,只需使用标准的推送和弹出(从 segue 和后退按钮)。

当你想去 A > B > C > A 时,你可以使用控制器 C 的 unwind segue。

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

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

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

这也会弹回 A。

【讨论】:

我目前确实在使用 segues 向各个方向移动。但导航不仅限于简单的前进和后退。例如,您可以从 A > B > C > A 或 A > C > B > C > B > A 移动。 我不知道' MyNewViewController *controller = segue.destinationViewController; ' 诡计。所以我猜你是说故事板会自动为我创建 VC 实例?我只需要在 prepareForSegue 中指出正确的:?我确实有需要在这些 VC 之间传递的数据,这就是我实施该方法的原因。 是的,没错。故事板为您创建 VC 并为您推送它。你在这里所做的只是拦截它并在它被创建之后但在它被推送之前添加更多信息。如果您在“initWithNibName”中有任何代码,那么您需要将其移至其他位置,因为不会调用此函数。 哦,这不是“技巧”,而是应该使用 segue 的方式 :D 如果您正在创建自己的 VC,那么您实际上是在为每个 segue 创建两个 VC。当您使用其他答案中的代码时,情况也是如此。你可能会回到你想要的地方,但你可能会发现你有未使用和看不见的 VC 被困在这个地方。 抱歉延迟回复。我想我现在理解了放松的过程,并同意这将是实现我的目标的一种很好的干净方式。不过我还有一个问题。我正在通过 UIImage 启动 segue(通过 UITapGestureRecognizer 技术以编程方式调用 segue)。在我看来,我无法将 UIImage 链接到 Exit(因此 unwindSegue),因为它不支持 action 属性。我尝试以编程方式调用 unwindSegue,但这会导致错误。有任何想法吗?我确实尝试将一个虚拟按钮链接到退出并按下按钮。【参考方案2】:

恕我直言,我没有看到使用 segues 的任何问题,它比其他任何东西都简单得多。如果您担心内存消耗,那么只需分析您的应用程序并查看它消耗了多少以及您的“内存压力处理程序”被调用的频率。

【讨论】:

根据真实用户的分析跟踪,内存警告经常被击中。仅适用于部分用户。但比执行的 segue 次数要多得多。 没有更多细节很难说它是什么。分析它并查看哪些对象占用了内存。它可能是一些用于背景的大尺寸图像......或其他东西。 我运行了一个配置文件。我是新来读这些的,所以很难说有什么记忆,但它确实随着每一次转折而增加。我的主搜索屏幕确实有一个带有图像的网格显示。我假设当我继续时,没有调用 viewDidUnload 方法?因此没有进行任何清理工作?我是否应该清理 viewDidUnload 在 prepareForSegue 方法中清理的大部分元素?最好将 VC 完全从堆栈中删除,因为我不知道如何重用它们,但否则我猜特殊的内存清理是下一个最好的事情。 这绝对是错误的。你永远不应该在 VC 之间使用 segues 来推送和弹出。你会得到到处都是内存错误。如果你想一次弹出多个 VC,你应该使用 unwind segues。【参考方案3】:

好的,我相信我已经弄清楚了。它似乎有效。

由于我一直返回到一个普通的 VC,我将代码放置在我想重新回到这个“根”VC 以清除 VC 堆栈的地方。

我仍然在我的正常代码中执行实际的转场

[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,但效果很好。

感谢您的帮助。

【讨论】:

不,这是错误的。几天没上。将编辑我的帖子。 嗯...此外,您永远不应该在 prepareForSegue 中创建视图控制器。我也会将此添加到我的答案中。 根据我迄今为止的测试和关于这个主题的其他讨论,我不相信我在这里所做的事情是错误的。例如参考这里:***.com/questions/11035809/…。感谢您提供的替代选项,如果我发现我遇到了问题,我会尝试一下。我将补充说明我正在使用模态序列。 我提供的代码直接来自几个 WWDC 会谈,而且您遇到的问题是为什么他们首先添加了展开 segues :) 您会发现它也清除了很多代码.我建议不要保留你所拥有的,以便将来让一切更清楚。您目前正在跳过不再存在的篮球:D【参考方案4】:

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

@IBAction func entryViewSelected(_ sender: UIButton) 

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

【讨论】:

以上是关于Segues 和从内存中清除历史 ViewControllers的主要内容,如果未能解决你的问题,请参考以下文章

ios小程序清除缓存

history历史命令

使用 Segues 感受糟糕的设计布局

linux中如何清除文件中旧的操作历史记录

如何将历史记录彻底清除掉

怎么清除电脑里所有的历史记录