Storyboard 和 XIB 文件被编译为二进制格式的 NIB 文件。当您部署应用程序时,可以在捆绑包中找到这些文件。
NIB 文件更容易理解。它们包含对象层次结构的数组。故事板更加复杂,因为它们包含整个场景,因此包含更多元数据(例如哪个视图控制器是场景中的初始视图控制器等)。 Segues 也是可解码的对象。
NIB 文件和故事板中定义的每个对象都有一个唯一的键(例如vXZ-lx-hvc
,编译时会附加类的名称,因此最终是LNViewController-vXZ-lx-hvc
例如)。
当您尝试加载 NIB 或 Storyboard 中定义的对象(通常是视图、视图控制器和 Segues,以及您可以在 Interface Builder 中定义的其他对象)时,类型的解码器UINibDecoder https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UINibDecoder.h创建后,它负责读取二进制 NIB 文件中的数据并将其解码为活动对象。然后分配一个对象并initWithCoder:
被调用,传递解码器。然后,该对象为其支持的每个属性调用各种解码方法。例如,表格视图将解码其样式、背景视图、单元格高度、委托等。解码完成后,NIB 加载程序调用awakeFromNib
通知对象它已从 NIB 加载。
故事板被编译成多个 NIB 文件,通常每个视图控制器一个 NIB 文件。当从故事板加载对象时,在内部UIStoryboard
具有要为特定视图控制器加载哪个 NIB 文件的元数据。当视图控制器被解码时(在其内部)initWithCoder:
,它加载整个视图层次结构、属性值、附加对象等。
最后,每个 NIB 文件(以及扩展的故事板)都能够包含键值信息,这些信息在对象成功解码后应用。
要实现您自己的类似系统,您需要提供一个类似的系统,该系统可以推断类型、分配对象,然后使用您自己的解码器对其进行初始化。由于视图和视图控制器实现了NSCoding
协议,您可以轻松调查它们支持哪些密钥,并创建解码器和数据格式来支持相同的密钥。
如果您希望遵循 NIB 和 Storyboard 加载流程,我建议您查看类转储、为关键方法设置断点并检查传递给方法调用的参数。在 64 位模拟器上调试时,汇编输出非常容易阅读,您可以使用以下命令轻松检查传递的参数po $arg1
为了self
目的,po NSStringFromSelector($arg2)
对于被调用的方法选择器,po $arg3
...对于以下参数。
建议从以下方法入手:
-[UIStoryboard instantiateViewControllerWithIdentifier:]
-[UIStoryboard instantiateInitialViewController]
-[UIStoryboard nibForViewControllerWithIdentifier:]
-[UINibDecoder decodeObjectForKey:]
(和另一个-decode***ForKey:
方法)
设置符号断点并查看传递的程序集和参数。
使用状态恢复时会发生非常相似的过程。不同之处在于,视图提供了一个编码器,并且它们将其属性编码给该编码器;在恢复期间,视图从状态恢复解码器恢复。