【问题标题】:iOS10: How to avoid memory leaks in a segue circleiOS10:如何避免segue循环中的内存泄漏
【发布时间】:2016-12-07 09:58:07
【问题描述】:

我的项目中有 4 个场景,page1 可以继续(类型为show)到page2,然后可以继续到page3,然后到page4,然后回到page1

从我的故事板中,您在 1 秒内就明白了这一点:

这四个场景的控制器类是ViewController

import UIKit

class ViewController: UIViewController {

    static var count: Int = 1

    var id = count

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        ViewController.count += 1
        print("ViewController#\(id) inited.")
    }

    deinit {
        print("ViewController#\(id) deinited.")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        print("ViewController#\(id) loaded.")
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("ViewController#\(id) appeared.")
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("ViewController#\(id) disappeared.")
    }

}

然后我完成segue循环后(page1> page2> page3> page4> page1),它输出:

ViewController#1 inited.
ViewController#1 loaded.
ViewController#1 appeared.
ViewController#2 inited.
ViewController#2 loaded.
ViewController#2 appeared.
ViewController#1 disappeared.
ViewController#3 inited.
ViewController#3 loaded.
ViewController#3 appeared.
ViewController#2 disappeared.
ViewController#4 inited.
ViewController#4 loaded.
ViewController#4 appeared.
ViewController#3 disappeared.
ViewController#5 inited.
ViewController#5 loaded.
ViewController#5 appeared.
ViewController#4 disappeared.

这不是我想要的。我认为我的堆中有 5 个ViewControllers(因为没有调用 deinit)。事实上,我们只需要 1 个ViewController 来控制page1。我应该怎么做才能销毁我的App堆中的4个无用的ViewController?

【问题讨论】:

  • 您可以更改 segue 到 page1 的代码以使 page1 成为根视图控制器,这将删除您拥有的整个视图控制器堆栈
  • 它们仍然存在于堆中,因为您使用“show”进行 segue,show 表示我想要控制器,为我保留它。如果你不想要它们,你可以使用“Present Modally”而不是“show”ant 然后关闭控制器。
  • 如果我通过执行从第 4 页连接到第 1 页的 segue 到达第一个视图控制器,我应该看到返回(弹出)按钮让我回到第四页吗?
  • @AhmadF 不,您不应该看到后退按钮。事实上,我的页面中没有返回按钮。

标签: ios swift uiviewcontroller segue


【解决方案1】:

介绍/解雇

注意:

如果您正在使用导航控制器,您可能想查看我对 Pushing/Popping 的回答。


第四个View Controller-中“Back To Page1”的动作,应该类似于:

@IBAction func backToPage01Tapped(_ sender: Any) {
    presentingViewController?.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
}

注意presentingViewController的个数为什么是三个,因为第四个是之前的View Controller个数。

如果你之前只有两个视图控制器,那么你必须向后链接两次,然后从两个视图控制器中调用dismiss:

presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)

等等……

【讨论】:

  • 像魅力一样工作!谢谢!
  • @Sayakiss 欢迎朋友 :) 希望这对你来说听起来合乎逻辑并且很乐意提供帮助。
  • 这不仅对我不起作用,而且窗口返回到我刚刚尝试关闭的视图控制器,我收到警告说我不应该在呈现视图控制器时关闭它(不在顶部)。
【解决方案2】:

推/弹出

注意:

此答案在您嵌入 导航控制器 时有效,如果不是(如本问题的情况),请查看我关于 @ 的答案987654321@.


我认为有两种方法可以执行“page4 to page1”的转场:

  • 在您的代码中的某处(我假设它在“Back To Page1”按钮的操作中),您正在调用performSegue 方法,

  • 你直接ctrl+拖到第一个ViewController。

如果你按照第一种方式,请将performSegue方法的代码替换为popToRootViewController方法,如下:

// "backToPage01Tapped" is just an example, it should be your method's name...
@IBAction func backToPage01Tapped(_ sender: Any) {
    navigationController?.popToRootViewController(animated: true)
}

如果您按照第二种方式,请转到情节提要,选择“page4 to page1”segue并将其删除!相反,在按钮上添加一个 IBAction,让类似于上面的代码 sn-p。

主要是针对你的情况,我建议popToRootViewController

弹出堆栈中除根视图之外的所有视图控制器 控制器并更新显示。

看来这正是你想要达到的目标。

【讨论】:

  • 我听从了你的建议,但我发现 navigationController 在我的情况下是 nil。我认为原因是我没有将视图嵌入到导航控制器中。
  • 我们的 UI 设计师给我的设计只是一些简单的页面,如我的示例中(没有返回按钮,没有标题),所以我不使用 navigationController
  • @Sayakiss 没错,好像没有嵌入导航控制器,所以导航被视为“呈现”而不是“推-显示”。
  • 但是问题是,当navigationControllernil,那么navigationController?.popToRootViewController(animated: true)就不会生效。让我留在第 4 页,不会发生任何转折。
  • 好吧,显示下一个视图控制器动画是什么样子的?是从右到左(推)吗?还是从下到上(呈现)?
【解决方案3】:

你所做的完全是错误的,不要使用前向 segue 从 4 回到 1,你必须使用 unwind segue,或者只是在导航控制器的 viewControllers 数组中设置 vc 1,如果你没有导航控制器,只需调用 vc1 的委托来关闭它正在呈现的控制器,或者将 rootViewController 设置回 vc1

【讨论】:

  • 对不起,我是iOS开发新手,只是不明白如何实现just call delegate to vc1 to dismiss it's presenting controller。能否请您详细解释一下,或者举个例子或一篇文章?
  • 最简单的方法可能是使用 unwind,delegate 有点难理解,可以阅读 unwind herehere
【解决方案4】:

如果您不打算执行 unwind segue 并返回到之前的 view controller 的最新状态,并且您想要解除分配先前的视图控制器,那么您实质上是将后面的视图控制器之一视为一个新的rootViewController,直到您重新分配AppDelegate 上的根视图控制器属性,由于rootViewController 对它有很强的引用,第一个视图控制器不会被释放。

UIApplication.shared.keyWindow?.rootViewController = VCTwo

【讨论】:

    猜你喜欢
    • 2019-06-29
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-27
    相关资源
    最近更新 更多