让我从开始陈述这个问题开始,说我的办公室里没有剩余的直立书桌。我把它们都翻过来了。我需要帮助来了解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
语句是绝对不必要的,但是我将它们包括在内是因为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
还是对super.viewControllers
的第0个索引中包含的同一对象的引用。
这对我来说没有意义,我需要帮助来了解正在发生的事情。
附录:我尝试用自己的超类重现此问题。我已经尝试过Swift超级类和Objective-C超级类。在这些情况下,我无法重现该问题。我只能用UINavigationController
复制(但是我不知道是否可能有其他Apple框架类复制此行为)。