【问题标题】:Dismiss ViewController after transition to release memory转换后关闭 ViewController 以释放内存
【发布时间】:2017-02-01 08:23:10
【问题描述】:

我想释放 ViewController 在关闭后使用的内存。我使用以下代码来展示新的 ViewController 并关闭旧的:

let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newVC: UIViewController = sB.instantiateViewController(withIdentifier: "MyVC")
self.present(newVC, animated: true, completion: { x in
    oldVC.dismiss(animated: false, completion: { _ in //oldVC: variable keeping track of currently visible view controller
        print("done")
    })
})

此代码成功呈现newVC,并在关闭oldVC 后打印done。但是,我的记忆力仍然保持在屏幕上显示oldVC 时的水平。
我做错了什么?

仅供参考

  • 我正在使用ENSwiftSideMenu
    • 由于我没有让它以不同的方式工作,我所有的 ViewController 都是 ENSideMenuNavigationController 的子类
  • 我收到关于分离视图和视图不在窗口层次结构中的控制台警告
  • 对于所有 ViewController,presentingViewControllerpresentedViewController 都是 nil

【问题讨论】:

  • oldVC的参考是什么?
  • “参考”是什么意思?它是一个全局变量,在每个 ViewController 的 viewWillAppear(_:) 方法中设置为 self。因此,它的类型为 `UIViewController
  • 尝试添加这一行 deinit { debugPrintln("Clean") }
  • 添加到 oldVC 的代码中?
  • 是的,在这种情况下,我们可以看到 oldVC 何时会真正被处理

标签: ios swift uiviewcontroller dismiss


【解决方案1】:

检查以下问题:

  1. 您应该在展示新的 ViewController 之前关闭旧的 ViewController,否则您将同时关闭新的 ViewController。
  2. Swift 使用 ARC 来管理内存。 oldVC 没有被释放,因为某些对象对它有强引用。举个例子,我有一个带有变量 tableView 的 ViewController。当 ViewController 释放时 tableView 将释放。但是同时如果你把它链接到另一个没有释放的ViewController,虽然之前的ViewController被释放了,但是tableView不会释放。

解决方案:

  1. 提交 UINavigationController 并使用 setViewControllers 管理 ViewController 的转换。
  2. 删除oldVC的无用引用

如果你真的不明白。你可以搜索:

  1. ARC
  2. UIViewController 转换

【讨论】:

  • 在演示前关闭时,我会留下一个空白屏幕。
  • @LinusG。因为在你调用了dismiss函数之后,新旧控制器都会被dismiss。
  • 那我该怎么办?
  • @LinusG。我的建议是将新旧控制器都放入 UINavigationController 以安排您的转换。如果你确实想要使用礼物。您可以尝试在没有动画的情况下关闭旧控制器,并在其完成关闭中显示控制器。
  • 后者正是我所做的。不过,我会尝试使用导航。
【解决方案2】:

您的oldVC 不会被释放,因为您的newVC(和任何UIViewController)默认保持对其presentingViewController 的强引用 - 提供它的控制器。如果不是这种情况,您将永远无法安全地关闭您的 newVC 而不会干扰视图层次结构。

就您的具体问题而言,为了释放您的旧视图控制器,我建议先解除oldVC,然后从堆栈中较早的另一个视图控制器显示您的newVC(可能是@ 987654328@)

【讨论】:

  • 嗯,我收到一个警告说……关于视图不在窗口层次结构中。直到现在我都无法解决这个问题,因为它从来没有引起任何问题,所以我真的不必这样做。
  • @LinusG。它确实是作为警告发出的(尽管根据我的经验,它可能会导致错误)
  • 来自rootViewController 的演讲让我有一个空白屏幕:(
【解决方案3】:

UINavigationController 的 push/pop 也有同样的问题。 @spassas 关于强引用是正确的,这就是您的 newVC 未被释放的原因。您应该仔细查看newVC

在我的例子中(用 Objective-C 编写)有另一个视图控制器被引用为推送视图控制器的私有属性(你的 newVC):

EventActionSheetViewController* actionSheet;

actionSheet 强烈引用推送的视图控制器 (newVC) 作为其委托:

@property (nonatomic) id<EventActionSheetDelegate> delegate;

我一直在检查我的应用程序的内存,发现推送的视图控制器在被导航控制器弹出后没有被释放。几个小时后,我将强引用更改为弱引用,结果如下:

@property (nonatomic, weak) id<EventActionSheetDelegate> delegate;

问题是我的推送视图控制器和它的EvenetActionSheetViewController 对彼此有很强的引用,并且不知何故没有让彼此解除分配。

我建议您检查您的newVC 是否有类似的强引用循环,并在可能的情况下将它们更改为弱引用。在 Swift 中使用weak letweak var 而不是let/var。希望这会帮助您找到错误。

【讨论】:

  • 我确实将我的声明更改为weak var,但这显然没有改变任何东西。
  • @LinusG。我认为我们需要查看newVC 的一些代码来提供帮助
  • 你需要什么?
【解决方案4】:

尝试用以下代码替换您的代码:

    let appDel = UIApplication.shared.delegate as! AppDelegate
    let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let newVC = sB.instantiateViewController(withIdentifier: "MyVC")
    appDel.window?.rootViewController = newVC
    appDel.window?.makeKeyAndVisible()

希望这行得通!

编辑: 您还可以通过将以下代码添加到所有视图控制器来检查旧的视图控制器是否正在取消初始化:

    deinit {
        debugPrint("Name_Of_View_Controller deinitialized...")
    }

编辑 2:

如果您想保留视图控制器中的呈现流程并且只想关闭最后一个视图控制器,即

在过渡中:masterVC -> oldVC -> newVC

从 oldVC 转换到 newVC 后,您想返回 masterVC,通过 oldVC 释放内存。 您可以将 masterVC 引用传递给 oldVC 并实现您想要的如下:

if(masterVC != nil) {
         oldVC.dismiss(animated: false, completion: {
            let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let newVC = sB.instantiateViewController(withIdentifier: "vc2")
            self.masterVC!.present(newVC, animated: false, completion: {
                print("done")
            })
        })
}

这适用于您所说的情况。

【讨论】:

  • 哪一个不适合你?第一个,还是第二个?您在 oldVC 中是否有任何强有力的参考资料?
猜你喜欢
  • 2018-12-09
  • 2018-09-25
  • 2015-01-31
  • 1970-01-01
  • 2012-03-15
  • 2013-01-02
  • 2011-09-18
  • 2013-02-11
  • 1970-01-01
相关资源
最近更新 更多