Search code examples
swiftmacosseguepopovernsviewcontroller

Swift MacOX - Popover segue creates multiple view controller instances without destroying them when they are dismissed


I'm creating a popover style view controller in storyboard like this

enter image description here

Then I click the button, the view controller shows and when I click anywhere outside, the view controller is "dismissed".

However, when I click the button again, a new instance of the view controller is lunched and the previous one is still running. I have tried deinit but it's not getting called when the view controller is "dismissed".

How can I either destroy the view controller instance when clicking outside, or "show" the already created instance?

My code in the view controller:

class FileTransViewController: NSViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(updateProgress), userInfo: nil, repeats: true)
        //print(123)
        print("\(self)")
    }

    deinit {
        print("destroyed")
        if let timer = timer {
            timer.invalidate()
        }
    }

    @objc func updateProgress() {
        print("updating progress")
    }

}

Solution

  • The problem has nothing to do with popovers. You are leaking because you retain the timer while the timer retains you — a classic retain cycle.

    To break the cycle, you must invalidate the timer. You cannot do this in deinit, because by definition it cannot be called until after you break the cycle. NSPopover.willCloseNotification might be a good opportunity.