创建UIViewController
的实例时,除非需要,否则不会加载其视图和所有IBOutlet
。
这意味着,与所有其他类不同,拥有完全初始化的实例并不意味着所有属性都被初始化和加载。
这是一种独特的行为,类似于异步加载但在绝对完成加载和初始化时没有任何委托或回调方法。
Cocoa(Touch)中没有其他对象遵循相同的逻辑,即使从UIView
加载nib
也会同步。
因此,在Apple的其他API的上下文中,viewDidLoad方法的命名是误导和/或不正确的约定是公平的吗?
答案 0 :(得分:2)
查看控制器加载是一种通常称为延迟初始化的模式。这种模式对于查看控制器并不是唯一的:它出现在Cocoa的几个地方,主要与基于nib / storyboard的UI有关。例如,您放入笔尖的任何自定义类(例如macOS上的UIView
子类或NSView
子类)都不是完全准备好的#34;直到调用awakeFromNib
方法为止。
当你加载一个笔尖或故事板时(或当视图控制器系统代表你这样做时),Cocoa(或Cocoa touch)从它们在nib中的存档表单中初始化对象,然后通过每个设置来查看任何{的值。 {1}}属性。因为这是一个两步过程(并且必须是,因为归档不能以nib所需的方式保留到其他对象的链接),所以存在对象存在的中间时间(即,它们& #39;已完成IBOutlet
方法和init
个链接,但尚未完全设置以匹配您在Interface Builder中创建的配置。
这里似乎有一些混乱,关于什么"初始化"手段。 Swift语言的要求以及ObjC中的强烈建议是,在初始化链完成运行时,所有属性/实例变量都具有定义值。换句话说,如果在初始化后获得属性或实例变量的值,通过阅读代码,您应该知道该值将是什么。
此定义与非ARC Objective-C的行为形成对比:如果您在初始化期间未分配实例变量,则其值为 undefined 。它们可能是零,它们可能是垃圾,它们可能被其他东西丢弃。
使用ARC的ObjC部分强制执行此问题的解决方案,确保所有变量初始化为零/零,即使您在初始化期间未手动分配它们也是如此。 Swift通过在编译时要求您在初始化中手动提供值来进一步强制执行它(通过在super.init
定义中指定它们,或者通过将它们声明为Optionals来指定它们被声明的属性。使其默认值为nil)。
因此,当您处理来自笔尖或故事板的内容时,拥有完全初始化的实例意味着所有属性都已初始化"根据语言定义 - 也就是说,它们的值是已知的。它并不一定意味着他们的价值观是你希望他们成为"。
特别是,视图控制器旨在用于延迟初始化场景,这些场景在故事板加载期间的持续时间超过""。例如,您可以设置整个互连的视图控制器网络(在导航堆栈,选项卡视图,主/详细拆分视图等中)。最初,这些VC实例已初始化并且知道它们的一些非IBOutlet属性(例如它们的标题,用于标记选项卡栏中的非活动选项卡)。但是昂贵的UI基础设施并不需要加载,直到系统要求VC的视图(通常在用户即将看到它时)。
答案 1 :(得分:0)
如果您正试图进入IBOutlets进行设置,我认为您可以从viewDidLayoutSubviews获得正确值的第一个调用。那个得到了很多,所以使用bool来只调用你的设置一次。