ViewController Doesn't Deinited

265 Views Asked by At

I have a FakeSplashController which does;

  1. ) Do a network request and wait for Its Result
  2. ) Show an animation then open SeconViewController

Something blocks this ViewController to be deallocated and deinit function doesn't get called.

In addition, AppInitService has a static func and It is called inside this SplashController. I also try to add [weak self] to network request. However, It also doesn't solve the problem.

class SplashViewController: UIViewController {

let logoImage:  UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "logo")
    imageView.contentMode = .scaleAspectFit

    return imageView
}()

let textLogo: UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "text-logo")
    imageView.contentMode = .scaleAspectFit
    return imageView
}()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    setupUI()
    networkRequests()

}

func networkRequests(){

    AppInitService().initAppRequest { [](result) in
        switch result{
        case .success(_):
            self.startAnimation()
            return
        case .error(let error):
            UIControlUtil.showErrorMessage(title: error.title, message: error.message, closeButton: true)
            return
        }
    }
}

func openApp(){
    let loginController = WelcomeViewController()
    guard let window = UIApplication.shared.keyWindow else {
        return
    }
    window.rootViewController = loginController
}

func startAnimation(){
    UIView.animate(withDuration: 0.8, animations: {
        self.logoImage.frame.origin.x -= 100
    }, completion: nil)
    UIView.animate(withDuration: 1,delay: 0.3,animations: {
        self.textLogo.alpha = 1
        self.textLogo.frame.origin.x += 50
    }, completion: { _ in
        self.openApp()
    })
}

deinit {
    print("Splash Deinited")
}
func setupUI(){
    self.view.backgroundColor = Color.NavigationBar.tintColor
    logoImage.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
    logoImage.center = self.view.center
    self.view.addSubview(logoImage)
    textLogo.frame = CGRect(x: 0,y: 0, width: 195, height: 80)
    textLogo.center = self.view.center
    textLogo.frame.origin.x -= 20
    self.view.addSubview(textLogo)
    textLogo.alpha = 0
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}
4

There are 4 best solutions below

1
aBilal17 On

You can first get all the view controllers in the array and then after checking with the corresponding view controller class, you can delete the one you want.

Here is small piece of code:

var navArray:Array = (self.navigationController?.viewControllers)!
navArray.removeAtIndex(0)
self.navigationController?.viewControllers = navArray

I think this will make your work easier.

0
Emre Önder On

The problem was I was creating this SplashController as a global and optional variable inside AppDelegate as;

var splashController: SplashController?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        splashController = SplashController()
        self.window?.rootViewController = splashController

        return true
    }

I make it as:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        let splashController = SplasController()
        self.window?.rootViewController = splashController
        return true
    }
0
Fogmeister On

You are capturing self in this block...

func networkRequests(){    
    AppInitService().initAppRequest { result in
        switch result{
        case .success(_):
            self.startAnimation() // HERE BE DRAGONS!
            return
        case .error(let error):
            UIControlUtil.showErrorMessage(title: error.title, message: error.message, closeButton: true)
            return
        }
    }
}

This is a potential cause of your memory leak.

You can be certain to not capture self by updating it to...

func networkRequests(){
    AppInitService().initAppRequest { [weak self] (result) in
        switch result{
        case .success(_):
            self?.startAnimation()
            return
        case .error(let error):
            UIControlUtil.showErrorMessage(title: error.title, message: error.message, closeButton: true)
            return
        }
    }
}
1
Virajkumar Patel On

Without using weak reference function cannot release self object so this function generate retain cycle instants of you can use weak reference.

// You can use weak reference certain to not capture self by updating it to...
func networkRequests(){
    AppInitService().initAppRequest { [weak self] result in
        guard let strongSelf = self else {
            return
        }
        switch result{
        case .success(_):
            strongSelf.startAnimation() // HERE BE DRAGONS!
            return
        case .error(let error):
            UIControlUtil.showErrorMessage(title: error.title, message: error.message, closeButton: true)
            return
        }
    }
}