首页 > 解决方案 > UINavigationController 中发生的魔术导致我的弱引用不恰当地归零

问题描述

让我从说我的办公室里没有直立的办公桌开始这个问题。我把它们都翻过来了。我需要帮助了解 Apple 中发生的UINavigationController导致我对零值的弱引用。


首先,在我更详细地解释问题之前,让我提供代码来重现。

首先,创建一个UINavigationController. 这个子类将持有对子类的弱引用UIViewController。它应该是对将作为根视图控制器传入的内容的引用。

为了证明我的精神错乱,我提供了一个重现问题的初始化程序以及一个解决我的问题的初始化程序。为了完整起见,我已经包含了编译所需的其他初始化程序。

class ChildNavController: UINavigationController {

    weak var weakRoot: UIViewController?

    init(withWeakFirst: Void) {
        let root = UIViewController()
        print("rootVC: \(root)")
        weakRoot = root
        super.init(rootViewController: root)

    }

    init(withWeakLast: Void) {
        let root = UIViewController()
        print("rootVC: \(root)")
        super.init(rootViewController: root)
        weakRoot = root
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

}

这些print语句是完全没有必要的,但我已经将它们包括在内,因为 a 的默认描述UIViewController包括内存地址。

现在......测试正在发生的事情的代码,这是相当直接的......

首先,测试我的第一个初始化程序:

let weakFirst = ChildNavController(withWeakFirst: ())
if let _ = weakFirst.weakRoot {
    print("weak first non-nil")
}
else {
    print("weak first nil")
    print("but the rootVC? \(weakFirst.viewControllers.first)")
}

控制台输出是:

rootVC: <UIViewController: 0x7f9de9f091a0>
weak first nil
but the rootVC? Optional(<UIViewController: 0x7f9de9f091a0>)

并将其与第二个初始化程序进行比较,在第二个初始化程序中,我只需更改调用 super.init 和分配到我的弱属性之间的顺序:

let strongFirst = ChildNavController(withWeakLast: ())
if let _ = strongFirst.weakRoot {
    print("weak last non-nil")
}
else {
    print("weak last nil")
    print("but the rootVC? \(weakFirst.viewControllers.first)")
}

以及为此的控制台输出:

rootVC: <UIViewController: 0x7f9de9d11f70>
weak last non-nil

这里只有三行相关的代码。第一行初始化一个正则UIViewController

let root = UIViewController()

这被分配到一个局部变量中。当初始化器返回时局部变量消失,所以如果没有创建外部强引用,视图控制器应该被释放。

然后我还有两行。

weakRoot = root

super.init(rootViewController: root)

不知何故,这两行的顺序决定了我的weakRoot属性是nil还是对 . 的第 0 个索引中包含的同一对象的引用super.viewControllers

这对我来说没有意义,我需要帮助了解发生了什么。


附录:我尝试用我自己的超类重现这个问题。我尝试过使用 Swift 超类和 Objective-C 超类。在这些情况下,我无法重现该问题。我只能重现UINavigationController(但是我不知道是否有其他 Apple 框架类可以复制这种行为)。

标签: iosswiftuinavigationcontrollerinitializationuikit

解决方案


推荐阅读