Search code examples
iosswiftuinavigationcontrollerautomatic-ref-countingweak-references

Weak reference getting zeroed out, but the object hasn't been deallocated


I have a weak instance variable holding onto a view controller in the UINavigationController.viewControllers stack.

My variable is automatically getting turned to nil, but the view controller hasn't been deallocated (since UINavigationController owns it).

Why is my weak reference getting zeroed?

class NavController: SuperNavigationController
{
    weak var weakViewController: UIViewController?

    required override init() {

        let rootViewController: UIViewController

        if (/* whatever */) {
            rootViewController = ViewController1(/*whatever*/)
            weakViewController = rootViewController
        } else {
            /* whatever */
        }

        /*** `weakViewController` is not `nil` at this point ***/

        /*** 
         *** This superclass function just does:
         ***   super.init(navBarClass:toolbarClass:)
         ***   viewControllers = [rootViewController]
         ***/
        super.init(rootViewController: rootViewController)
    }

    // Without this, I get an "unimplemented initializer" exception
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

...
}

But as soon as I get to viewDidLoad, weakViewController is nil, even though self.viewControllers.first is still the exact same object I had when initializing.

Is there something weird about the way UINavigationController owns its viewControllers?

EDIT: I managed to identify and fix the cause at a shallow level (see my answer below), but I'd still like to know why this happens. I'll happily accept and upvote an answer which can explain what's going on!


Solution

  • Calling super.init() was causing the weak subclass instance variables I had set to be zeroed out.

    I fixed this by waiting to set weakViewController until after the call to super.init()