Anatomy of a Nib File
A nib file describes the visual elements of your application’s user interface, including windows, views, controls, and many others. It can also describe non-visual elements, such as the objects in your application that manage your windows and views. Most importantly, a nib file describes these objects exactly as they were configured in Xcode. At runtime, these descriptions are used to recreate the objects and their configuration inside your application. When you load a nib file at runtime, you get an exact replica of the objects that were in your Xcode document. The nib-loading code instantiates the objects, configures them, and reestablishes any inter-object connections that you created in your nib file
以上是苹果官方文档对nib的晦涩的解释,言简意赅的介绍了一下nib是用来描述应用程序的软件界面,视图,窗体等组件元素。那么nib到底是什么?以及和现在我们说的XIB有什么关系呢,先解释nib,Xcode 3.0 之前 Interface Builder 创建的文件是二进制格式 nib,nib 代表 NeXT Interface Builder,但是二进制并不是那么好管理,易读性也不强,Xcode 3.0 之后,为了与时俱进Interface Builder 使用了一种新的文件格式 xib(XML Interface Builder)xib 使用了 XML,在工程编译的时候再转换成 nib。XML资源文件更容易被开发者所接受,方便开发,也利于解决冲突。XIB查看xml格式见以下截图。
Nib Files
Nib files play an important role in the creation of applications in OS X and iOS. With nib files, you create and manipulate your user interfaces graphically, using Xcode, instead of programmatically.
以上是苹果官方文档对XIB的评价和定义:在OS X和iOS应用程序的创建中Nib文件扮演着重要角色,在Xcode开发工具中用nib文件,你创建和操作用户界面图形化,而不是以编程方式。这句话代表了苹果对XIB推荐和重视的态度,确实XIB的出现给开发者搭建软件界面视图,不用写繁琐的布局胶性代码带来了福音。XIB是软件发展的趋势,让编程变得简单,便捷,全民都是开发者。
XIB文件的创建
目前在我们iOS应用程序的开发中,XIB的使用基本都是基于View类和Controller类去创建的。当然只要是展示界面的,都可以用XIB去描述,UIWindow也是继承UIView的,此处只描述View类,Controller类。
基于Controller类
(1) 创建基于UIController子类时直接勾选创建XIB文件。此时你可以在XIB文件中拖入控件,在AppDelegate.m文件中创建该控制器就行了,cmd+R运行正常。
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
ZLController *vc = [[ZLController alloc] init]; // 这种方式,直接用alloc init方式创建就行了。
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
(2) 基于已经创建的UIController子类单独创建与之对应的XIB文件。
有时候我们会有这样的需求,需求变动,想在现有的控制器类创建XIB去描述,cmd+n选择User interface —>View(Empty)—>双击你要选择与之相关联的类(不用为XIB文件重新命名)。
注意:此时如果还是像上面的方式去创建XIB,直接运行会报错。错误提示我们在创建控制器的时候无法加载nib形式的视图View。报错截图如下。
在这儿有两种处理方案,切记!!!当然会涉及一个很重要又不好说清楚的知识点Nib File’s Owner,先看处理方案的操作,后面会详细介绍Nib File’s Owner。
方案一:
2.1 还用 alloc init的创建方式,只是需要设置新建XIB的File’s Owner所关联的类,和File’s Owner所管理的View。
解释上面截图的流程:
先选中noXibViewController.xib,点击File’s Owner,点击右侧属性栏中的第三个标签custom class,关联类,然后点击左侧的File’s Owner,按住command键,拖拽至下面的View视图,会出现Outlets->View,点击View,这样就设置了控制器VC所管理的View,这是关键的一步骤,解决了上面Xcode报错,而中间一部设置File’s Owner的custom class 只是这一步的桥梁和过渡,只有先找到File’s Owner所对应的控制器之后才能找到对应的View视图。因为现在程序没有运行,不会加载到内存中,所以如果你不为File’s Owner设置关联类,你直接拖拽设置File’s Owner的Outlets是不成功的,老铁们可以尝试一下。如果大家还不理解你可以选中File’s Owner,删除右边属性标签栏的custom class,cmd+R 运行成功。可能有些老铁还是迷茫,这个File’s Owner所关联的类到底是怎么回事呢?其实,当我们运行程序时,在AppDelegate.m文字中,我们用alloc init的方式创建了VC控制器,Xcode会自动关联寻找与此类(noXibViewController)同名的xib资源文件,如果找到了会自动加载,所以才不会报错。特殊情况,如果你为XIB起名和要关联的类名不相同,用alloca init 去创建XIB 系统是找不到该xib文件的,当然也会报错,切记!!!
这儿的处理方式,分两步走:
(1)修改创建VC的方式,不用alloc init了,明确的告诉它需要加载的XIB名称
noXibViewController *vc = [[noXibViewController alloc] initWithNibName:@"View" bundle:[NSBundle mainBundle]];
(2) 在控制面板中关联类和设置XIB的File’s Owner(注意一定要设置XIB父视图,而不是subViews)。此处截图上上面类似。
基于View类
初级的用法和基于控制器Controller的用法一样的,
(1) 新建View的子类.h,.m文件
(2) 新建XIB文件,选中对应的类文件
(3) 关联XIB文件和类文件(这所以要关联类文件,是为了方便连线,代码控制XIB)
(4) 在控制器类加载xib文件(此处不讲解封装性,只讲解原理)
这儿在控制器VC中加载XIB基本有两种方案。
self.view.backgroundColor = [UIColor whiteColor];
// 方案一 加载对应的XIB文件,设置owner(nil,0,self) 效果是一样的,可能苹果内部做了判断,默认都是self(本控制器),也就是这个通过XIB实例化的View的资源文件的所有者和用户交互的管理者。
customView *customView = [[[NSBundle mainBundle] loadNibNamed:@"customView" owner:self options:0] objectAtIndex:0];
// 方案二 1.先取出nib文件 2.nib对象方法取出对应数组中想要的XIB资源文件
UINib *nib = [UINib nibWithNibName:@"customView" bundle:[NSBundle mainBundle]];
UIView *customView = [[nib instantiateWithOwner:self options:0] lastObject];
customView.frame = CGRectMake(0, 64, self.view.frame.size.width, customView.frame.size.height);
[self.view addSubview:customView];
注意:基于View的XIB文件加载方式只能是加载资源文件的方式,这点和基于Controller的 alloca init 加载XIB的方式是不同的,可能是苹果内部没有做处理,它的父类不会去匹配和此类(customView)同名的XIB文件,所以不能用alloc init的方式去加载。
XIB自定义布局控件
XIB是以可视化视图的方式创建了软件界面,简单的说我们用Interface Builder 方式创建了UIView对象就定义了View的大小,位置,背景,图层(注意:用XIB拖拽控件只能是往View上拖拽,XIB目前只支持这种形式,例如,UIImageView上添加UIButton是能用代码的方式添加),那么,initWithFrame方法是不会被调用的,一般情况下我们用代码的方式创建View或者UIView的子类对象时候才会调用initWithFrame方法,
initWithFrame方法用来初始化并返回一个新的视图对象,根据指定的CGRect
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];// 先调用父类的initWithFrame方法
if (self) {
// 再自定义该类(UIView子类)的初始化操作。
_button = [[UIButton alloc] initWithFrame:self.bounds];
[_button setFrame:CGRectMake(0, 0, 320, 480)];
[self addSubview: _button];
}
return self;
}
当我们用Interface Builder创建View的时候不会再去调用initWithFrame方法,但是XIB资源文件创建保存的过程会调用,所以可以把以前放在initWithFrame方法中做的事情放在这个函数里面处理,可以重新定义视图。
- (instancetype)initWithCoder:(NSCoder *)aDecoder
当然同样也会调用下面的函数,从字面的意思可以看出awakeFromNib在initWithCoder方法之后调用,此刻是唤醒XIB视图文件,可以在此函数中进行调整,这样的话你就可以根据需求进行编码了。
-(void)awakeFromNib
{
[super awakeFromNib];
// 布局
}
总结
XIB是苹果官方推荐的视图开发方案也是我们开发者必备技能。此篇文章初对XIB做了简单介绍,创建两种不同XIB文件需要注意的事项,流程,归纳和比较。下一篇文章将会继续讲解XIB,主要是XIB一些高级用法。
-END-
文章写得有点乱,Markdown语法还不是太熟练,喜欢的老铁们,评论走一走,敬请留言,如果文章有不妥之处我会及时更正。