当使用可视化方式创建View Controller时,我们通常都是使用Storyboard进行的。我们通常会在同一个Storyboard中创建一大堆的View Controller,这样又容易导致代码冲突,因此有时候我们可以考虑直接使用Nib来创建单个View Controller。步骤如下:
步骤一:创建Nib
有两个方法可以创建这样的Nib。
方法一:使用Xcode的View Controller模板(推荐)
点击Command + N创建UIViewController的子类时,选中“Also create XIB file”,Xcode就会自动生成并配置好一个同名的Xib文件,我们直接往里面拖控件、拉线就可以了。
方法二:手动创建Xib文件
手动创建Xib文件有点麻烦,但能对Xib的机制有更多的理解。假设此处的UIViewController的子类名为NibViewController
,手动创建的步骤如下:
-
点击Command + N创建一个空白的Xib文件,可以任意命名,但通常来说我们让它与UIViewController的子类同名,即NibViewController。
- 打开这个新建的Xib文件,向其中拖入一个UIView控件。注意,这里拖入的是UIView,而不是UIViewController!
- 点击File's Owner,在Identity inspector中将它的Class设置为
NibViewController
,在Collection inspector中将view与刚才拖进来的UIView控件连起来。注意,这里不需要设置那个UIView控件的class。
完成上述步骤之后,这个Xib文件就配置好了。接下来按正常流程往上面的UIView控件中添加其他控件、设置属性、往NibViewController
中拖线就行了。
上面的配置中有个很有意思的一点,那就是设置“File's Owner”,那“File's Owner”是什么?
- 设置Nib的File's Owner,而不设置UIView的class时,就可以基于Nib创建UIViewController
- 设置UIView的class,而不设置Nib的File's Owner,就是基于Nib创建UIView。
“File's Owner”是什么
Apple官方文档对“File's Owner”的描述如下:
One of the most important objects in a nib file is the File’s Owner object. Unlike interface objects, the File’s Owner object is a placeholder object that is not created when the nib file is loaded. Instead, you create this object in your code and pass it to the nib-loading code. The reason this object is so important is that it is the main link between your application code and the contents of the nib file. More specifically, it is the controller object that is responsible for the contents of the nib file.
In Xcode, you can create connections between the File’s Owner and the other interface objects in your nib file. When you load the nib file, the nib-loading code recreates these connections using the replacement object you specify. This allows your object to reference objects in the nib file and receive messages from the interface objects automatically.
对于File's Owner,需要记住以下两点,
File's Owner对应的是这个方法的
owner
,Bundle.loadNibNamed(_ name: String, owner: Any?, options: [AnyHashable : Any]? = nil)
当nib文件被加载之后,你希望能在代码中控制它内部的控件,可以将某个自定义Class(通常是UIViewController的子类)设置为这个Nib文件的File's Owner,然后将Nib文件的子控件的Outlet设置到File's Owner的class中。
对于第二点,大家可能会疑惑,为什么要设置File's Owner,我们平时都是直接设置UIView的class的啊?没错,当我们使用Nib来创建自定义的UIView时,是将这个UIView控件的Class设置为我们自定义的UIView class类型,但当我们要使用Nib来创建自定义的UIViewController时,就必须要设置File's Owner了,因为这种方式下,我们是将一个UIView控件,而不是UIViewController控件,拖到Nib文件中,作为最底层的superView,然后再UIViewController子类中设置控件的Outlets,而我们显然不能将一个UIView控件的class设置为一个UIViewController子类,这时就只能通过File's Owner来实现了。
步骤二:初始化UIViewController
UIViewController
有一个nibName
的property,当该property不为空时,UIViewController.loadView()
会从依据那个nib文件加载UI。nibName
的设置有以下方式,每种方式都代表了一种初始化NibViewController
的方法。
方法一(推荐):UIViewController.init(nibName:bundle:)
使用UIViewController.init(nibName:bundle:)
来显示地指定nibName
。
let controller = NibViewController(nibName: "NibViewController", bundle: nil)
方法二:UIViewController.init()
+ nib文件自动匹配
使用UIViewController.init()
时,若iOS能在bundle中根据view controller的class name匹配到一个nib文件,就会隐式地指定nibName
。nib文件的匹配规则如下:
- 如果view controller的class name以
Controller
结尾,比如NibViewController
,那么系统就会匹配不包括Controller
的nib文件,即NibView.nib
。 - 系统还会匹配完全同名的nib文件。比如,对于
NibViewController
,匹配NibViewController.nib
。这也是为什么推荐nib文件与view controller同名的原因。
// If the nib file name is NibView.nib or NibViewController.nib
let controller = NibViewController()
方法三:UIViewController.init()
+ override var nibName: String?
我们还可以通过override``nibName
的方式显示的指定nibName
。假如NibViewController
对应的nib文件是RandomNibName.nib
,那么可以使用以下代码创建NibViewController
的实例。
class NibViewController: UIViewController {
override var nibName: String? {
return "RandomNibName"
}
}
let controller = NibViewController()
需要注意的是,当我们override var nibName: String?
后,即便使用UIViewController.init(nibName:bundle:)
,也无法修改nibName
。