如何通过 ViewControllers 管理和释放内存

Posted

技术标签:

【中文标题】如何通过 ViewControllers 管理和释放内存【英文标题】:How can I manage and free memory through ViewControllers 【发布时间】:2018-01-04 13:52:29 【问题描述】:

我面临一个大问题,我找不到解决方案的唯一原因是我缺乏关于 swift 和 swift 内存管理的知识。所以这是我的担忧。我正在使用 swift 4.0 和 ios 9.3

我实际上正在制作一个带有登录/注销的图片库应用程序。基础应用。 我在 cleanSwift 中工作,所以我没有那些巨大的 ViewControllers。

我的应用程序在 3 个 VC 中是独立的:登录、图库和设置(其中包含 LogOut)。

这是我的问题。当我注销时,我想创建一个新的 loginVC 并清除所有以前的 VC。 所以我有我的 cleanMemory 函数,它将所有 UIImage 设置为 nil

func cleanMemory(request: Gallery.Request)  // Interactor
    worker.cleanMemory(completionHandler:  (Value) in

        self.interventions?.removeAll() // Interventions contains UIImages
        self.interventionsSelected.removeAll() // InterventionsSelected contains UIImages

    )


然后我删除 UIImage 和 VC 的其余部分

func cleanMemory() 

    interactor?.cleanMemory(request: Gallery.Request())
    self.displayedInterventions.removeAll() // displayedInterventions contains UIImages
    interactor = nil
    router = nil
    self.removeFromParentViewController()
    self.navigationController?.popViewController(animated: true)

但是当我创建我的新 LoginVC.. 我的 RAM 没有减少.. 当我检查应用程序内存时,没有一个 VC 被删除.. 当我执行循环注销/登录 3 次时,我的应用程序崩溃,因为我没有很好地管理我的 RAM_

那么我哪里错了,为什么??

感谢您的回答。

编辑:我遇到了 2 个问题:

我的 completionHandler 让我的 VC 保持活力 我正在用 .present 切换 VC,以便将我的 VC 保留在内存中。

所以你应该这样改变VC:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationVC = storyboard.instantiateViewController(withIdentifier: "LoginController")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = destinationVC

【问题讨论】:

当用户点击 SettingsVC 中的 Logout 时,如何再次返回 LoginVC? 也许你有一个保留周期? 绝对是@ZaidPathan。我有一个注销按钮,我创建了一个新的 LoginVC,我将我的 loginVC 设置为应用程序的根目录并切换到它。 我认为我没有保留周期@Francis.Beauchamp。我所有的 VC 链接都很薄弱。我的问题更多是关于在这些情况下内存和“空闲”内存是如何工作的 您可能想看看 Instruments,它可以帮助您找到内存问题。这是一个关于它的教程的链接。 raywenderlich.com/166125/… 【参考方案1】:

要从内存中删除viewController,您只需将其从导航堆栈中删除即可。因此,当您调用 navigationController?.popViewController(animated: true) 并返回之前的视图控制器时,您已经销毁了该控制器。

那么,

这是我的问题。当我注销时,我想创建一个新的 loginVC 并清除所有以前的 VC。所以我有我的 cleanMemory 函数,它将所有 UIImage 设置为 nil

注销时最好停止所有请求,但您不需要对 UI 进行任何更改,因为这需要一些时间并且不需要“从内存中删除控制器”。如何检查视图控制器是否完全从导航堆栈中删除?只需在deinit func 中编写print 语句,编译代码并从该视图控制器返回。

deinit 
    print("ViewController deinit")

如果print 工作正常(您可以在 xcode 控制台中看到文本),您将获得结果 - 控制器已从导航堆栈中删除,但如果没有 print 结果,您可能忘记正确管理您的闭包.例如

worker.cleanMemory(completionHandler:  (Value) in
    ...
)

当您认为控制器已被释放时,此闭包可能会保留您的控制器,这意味着您的控制器存在于内存中的某个位置。要防止这些retain cycles,您需要使用[unowned self][weak self](这个关键字只需google,很容易理解),如下所示:

// or you can use `[unowned self]`
worker.cleanMemory(completionHandler:  [weak self] (Value) in
    guard let `self` = self else  return  // only for `weak` way
    ...
)

因此,在这种情况下,在 pop from navigation stack 左右操作之后,没有什么可以让您的控制器保持活动状态。 这些是编写管理良好的代码时应遵循的简单规则。

【讨论】:

哦。我得到它。这很有意义。我没有考虑维护 VC 存在的 completionHandler。我遇到了另一个问题,我的路由中有保留周期,我正在存储 VC 并使用“.show”进行切换。这也是有道理的,我修复了它并通过更改为 root 来更改我的路由。再次感谢您,我将编辑并关闭我的帖子! :)

以上是关于如何通过 ViewControllers 管理和释放内存的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 viewControllers 的导航控制器设置自定义 segue 操作

如何从它的项目 ViewControllers 访问 UITabBarController 的变量

无法通过 UINavigationcontroller.viewControllers 更改类的属性

Xcode:如何将对象从一个 viewControllers 视图移动到另一个 viewControllers 视图?

如何从 navigationController(viewControllers/stack) 弹回指定 viewController?

Linux堆内存管理深入分析(下)