UINib(iOS):能否从单个nib文件实例化多个视图?
关于UINib实例化返回数组的深层解析
你观察得特别细致!没错,UINib的instantiate(withOwner:options:)方法返回数组,这就明确告诉我们:一个nib文件完全可以包含多个顶级对象(包括视图)——只是日常开发中我们大多用nib来创建单一组件,所以习惯性只取数组第一个元素,才会让人产生“nib只能有一个视图”的错觉。
一、数组里的其他元素是什么?
这个数组包含了nib文件中所有未被嵌套在其他对象内的顶级对象,具体可以分为两类:
- 顶级视图:比如你在XIB画布上拖了两个独立的UIView(没有父视图),这两个都是顶级视图,都会被实例化并加入数组。
- 非视图类顶级对象:nib不仅能存视图,还能序列化任何NSObject子类(甚至是自定义非视图类)。比如你拖一个“Object”控件到XIB,指定它的类为自定义的
DataManager,这个对象也会被实例化后放进数组里。
二、为什么日常开发只用到第一个元素?
因为绝大多数场景下,我们用nib是为了创建独立的UI组件(比如自定义Cell、弹窗视图、工具条等),这类需求只需要一个核心视图作为入口,取第一个元素就足够满足需求,这种用法也最直观、最符合常规开发习惯。
三、补充问题:多视图如何关联到UIView子类?
File's Owner只有一个,但这并不影响我们关联多个视图,有两种常见方式:
方式1:直接给每个顶级视图指定自定义类
不需要依赖File's Owner,直接在XIB的Identity Inspector里给每个顶级视图设置对应的自定义类即可。实例化后,数组里的元素就是对应子类的实例,直接强转就能使用:
// 实例化nib let nibObjects = UINib(nibName: "MultiViewNib", bundle: nil).instantiate(withOwner: nil, options: nil) // 强转成对应的自定义视图类 let customViewA = nibObjects[0] as! CustomViewA let customViewB = nibObjects[1] as! CustomViewB
方式2:通过File's Owner关联多个视图
如果需要统一管理这些视图,可以在File's Owner的类中添加多个IBOutlet属性,再在XIB里建立关联:
- 定义Owner类:
class MultiNibOwner: NSObject { @IBOutlet weak var viewA: CustomViewA! @IBOutlet weak var viewB: CustomViewB! }
- 在XIB中,把
File's Owner的类设置为MultiNibOwner,然后分别把两个顶级视图拖到对应的IBOutlet上; - 实例化时传入Owner对象:
let owner = MultiNibOwner() // 实例化nib时,系统会自动把视图关联到Owner的属性上 _ = UINib(nibName: "MultiViewNib", bundle: nil).instantiate(withOwner: owner, options: nil) // 现在可以直接通过owner访问两个自定义视图 owner.viewA.doSomething() owner.viewB.doSomethingElse()
理论背景小补充
NIB/XIB本质是一种对象序列化文件,它存储的是一组对象的属性、层级关系、关联关系等信息。当调用instantiate方法时,系统会解析整个文件,把所有存储的顶级对象逐一实例化,同时恢复它们的配置、子视图结构以及和File's Owner的关联。返回数组正是这种设计的直接体现——nib可以承载多个独立的顶级对象,而非只能有一个。
内容的提问来源于stack exchange,提问作者Yotam
相关产品推荐
相关产品推荐

