How can I manage and free memory through ViewContr

2020-08-01 06:15发布

问题:

I'm in front of a big issues, and the only reason I can't find a solution is because my lack of knowledge about swift and memory management in swift. So here is my concerns. I'm working in swift 4.0 and iOS 9.3

I'm actually making a picture gallery app with login/logout. Basic application. I'm working in cleanSwift So I don't have those HUGE ViewControllers.

My application is separate in 3 VC : The login, the gallery and the settings (which contains the LogOut).

Here is my problem. When I log out, I want to create a new loginVC and clear all previous VC. So I have my cleanMemory function which set all the UIImage to nil

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

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

    })

}

and then I delete the rests of the UIImage and the 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)
}

But when I create my new LoginVC.. my RAM didn't decrease.. And when I check the app memory, not a single VC was deleted.. And when I execute the loop Logout/Login 3 times, my app crash because I'm not well managing my RAM_

So where did I get wrong, and why ??

Thanks you for your answer.

EDIT: I was having 2 problems :

  • My completionHandler was keeping my VC alive
  • I was switching VC with .present, so that was keeping my VC in memory.

So you should change VC like that :

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

回答1:

To remove viewController from memory you simply need to remove it from navigation stack. So when you call navigationController?.popViewController(animated: true) and back to previous view controller you already destroy that controller.

Then,

Here is my problem. When I log out, I want to create a new loginVC and clear all previous VC. So I have my cleanMemory function which set all the UIImage to nil

on logout it's good practice to stop all request but you don't need to do any changes to UI, because it takes some time and it doesn't need to "remove controller from memory". How to check if view controller completely removed from navigation stack? Simply write print statement in deinit func, compile code and go back from this view controller.

deinit {
    print("ViewController deinit")
}

If this print works fine (you can see text in xcode console), you achieve the result - controller has been removed from navigation stack, but if there is no print result you probably forget to right manage your closures. For example

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

this closure may hold your controller when your think that controller already deallocated and it means that your controller present somewhere in memory. To prevent these retain cycles you need to use [unowned self] of [weak self] (just google for this keywords, it's very easy to understand) like this:

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

So, in this case there are nothing that can hold your controller alive after pop from navigation stack action or so. These are simple rules that you should follow to write well managed code.



标签: ios swift memory