1.IB是什么?
Interface Builder 是一种通过图形化界面搭建UI的方式,并把窗口、菜单栏以及窗口上的各种控件的对象都“冻结”在了一个 NIB文档里;程序运行时,这些对象将会“苏醒”。
在终端下我们可以看到,NIB 其实是一个目录。它里面有两个也是后缀为 NIB 的文件:designable.nib 和 keyedobjects.nib。前者是一个 XML 文档,而后者则是一个二进制文件。Interface Builder 3 之后,引入了新的文档格式:XIB。它是单一的 XML 文档,也就是一个纯文本文件。纯文本文件的好处是显而易见的。嗯,就是便于源代码版本管理。现在最新版本的 Xcode 在创建项目时,已经默认使用 XIB 格式的文档了。
不论在 Interface Builder 中选择的是 storyboard 还是 xib 格式,Xcode 编译后都将得到一个供程序运行时使用的经过编译的 NIB 文件。
2.storyboard开发该怎样做?
2.1.程序启动的过程
首先iOS应用程序默认的启动过程是:
①.先加载Main函数
②.在Main函数里的 UIApplicationMain方法中,创建Application对象 创建Application的Delegate对象
③.创建主循环,代理对象开始监听事件
④.启动完毕会调用 didFinishLaunching方法,并在这个方法中创建UIWindow
⑤.如果有storyboard,会根据info.plist中找到应用程序的入口storyboard并加载箭头所指的控制器
⑥.设置UIWindow的根控制器是谁,如果Storyboard和手码都设置了根控制器,手码设置的根控制器会把手码的给替换了。
⑦.显示窗口
如果是纯代码的项目将不会有第五步。会直接在didFinishLaunching方法中找到UIWindow设置的根控制器,通过创建时的类型来决定控制器的类型。如果项目中使用了interface Builder的图形化界面,那么在程序启动过程中会经历第五步,并且需要将storyboard中的控制器与自己建立的类相关联。
2.2.方法调用的区别
使用纯手码开发的方法调用顺序为:
控制器 + (
void
)load;
控制器 + (
void
)initialize;
控制器视图 - (instancetype)initWithFrame:(CGRect
)frame;
控制器视图 - (
void
)awakeFromNib;
控制器 - (
void
)loadView;
控制器 - (
void
)viewDidLoad;
如果项目开发使用的是storyboard开发,也就是说这个控制器在storyboard中有一个对应的控制器图像化界面,那么将不会调用initWithFrame方法。这也就是把旧的纯手码项目整改成storyboard开发的困难所在。需要check所有initWithFrame中的代码。将其转移到可以调用到的方法中。并且如果在AppDelegate里设置了控制器的View。那么在控制器中将不会调用loadView方法。
3.模拟Storyboard开发部分需求
该部分内容牵扯到公司内部代码,暂不公开。
4.使用自动布局的约束替换frame开发
4.1旧方法中存在的问题
当下的旧版本存在大量的frame代码。旧代码块中,存在大量的纯数字,并且直接在创建时给予一个固定的frame,在屏幕的大小不同时,还需要将frame大小进行判断来改变。如果使用按百分比缩放的方法来处理不同屏幕尺寸,虽然可能比前一种方案方便,但界面的控件会出现部分像素的失真与模糊。
并且假设代码已经写的很整齐,但是当iPhone发布了一种新的机型对应一个新的屏幕尺寸时,又需要将代码拿出来对所有的控件大小再加入一种尺寸的判断。代码的维护难度较大。
4.2解决的方法-使用约束来替代frame开发
使用自动布局的约束开发
1 2 3 4 5 |
|
4.2.1自动布局与自动伸缩的区别
自动布局是iOS6.0之后才有的功能,在这之前是使用自动伸缩来完成自适应屏幕的适配。两者的区别主要是:自动伸缩只能够将子控件与父控件之间设立联系类似与自动填充,而自动布局则更加灵活可以将子控件与兄弟控件之间设立依赖关系。
在使用自动布局之前需要先关闭autoresizing自动伸缩以防止约束的冲突。
4.2.2使用约束开发的思路
如上面的代码,一般情况下一个控件需要设置四条约束。上面先设置了上下左右四个方向的依赖,然后取消了顶部,再次设置了一个自身的高度约束以达到正好四条约束。 但也有一些特殊的控件比如button和label可以先设置sizetofit自适应大小,然后只需要再设置两条约束即可。
4.2.3使用约束的好处
一旦设置了约束,则该控件就不再存在frame这个概念了,并且大小可以完全依赖屏幕的大小和自己依赖控件的位置而自动产生改变。即使出现新的屏幕尺寸代码也不需要做任何修改就能自动适配,且屏幕像素不失真。此种方案使得以后代码的维护更加方便。
4.3最佳的做法
回归到本文的主题还是关于IB图像化界面和手码的界面的。上面的4.2仅仅是讲述了在代码中添加约束,这仅仅是添加了比较简单的约束,如果复杂的约束也是需要写非常冗长的代码的,如果在图形化界面搭建自动布局将会有更高的效率。和更清晰的显示。
设置自动布局后的项目并没有对横屏进行特殊处理但是横过来,都可以完美适配。
并且所有的约束都有自己的图形化界面可供修改,通过主界面能很快找到对应的某条约束进行修改,这比在代码中翻来覆去的找某一行效率要高的多。
选择一个控件后,可以再右边的Constraints中选择一条约束,然后对应下面的Edit就可以进行修改非常方便。
使用Storyboard搭建约束的另一个好处就是:加载在拖动中失手移动了某个控件的位置,Xcode都会提示该控件的正确位置,并建议你如何还原。换言之,就是每一个控件都被锁在某一个位置,相比之前的frame设置的一个暂时的位置,就像城管和中国人民解放军站在某处的区别。
5.IB和storyboard究竟好在哪里?
5.1 项目结构清晰
纯代码开发中虽然左边的项目组成中分了较细的文件夹,但内部的文件比较多找起来非常麻烦,如果需要改某个页面的需求,基本都需要通过xcode提供的搜索功能来搜索所需的页面,或搜索所需的方法。但是可以看出如果项目比较庞大,利用搜索功能也很难找到特定的类或方法。
但是如果使用IB-Storyboard开发则会是这样。我以前一个联系代码的Storyboard页面,Storyboard顾名思义,就是一个故事板,描述一个故事的前因后果或故事的发展关系。整个结构的清晰程度是纯代码所达不到的。你可以清楚的看到各个页面之间的联系,虽然长期维护此代码的工程师不用IB页面也能清楚的知道各个页面跳转关系,但需要他再修改过程中思维高度集中。并且假如项目交接给另一位工程师维护,则所有的业务想在抓起来非常困难。
5.2 代码少就是bug少
iOS5之后Apple提供了一种全新的方式来制作UI,那就是StoryBoard。简单理解来说,可以把StoryBoard看做是一组viewController对应的xib,以及它们之间的转换方式的集合。在StoryBoard中不仅可以看到每个ViewController的布局样式,也可以明确地知道各个ViewController之间的转换关系。相对于单个的xib,其代码需求更少,也由于集合了各个xib,使得对于界面的理解和修改的速度也得到了更大提升。减少代码量就是减少bug量,这也是程序开发中的真理之一。
在Xcode5之后,StoryBoard已经成为新建项目的默认配置,这也代表了Apple对开发者的建议和未来的方向。WWDC2013的各个Sample Code中也基本都使用了StoryBoard来进行演示。可以预见到,之后Apple必定会在这方面进行继续强化,而反之纯代码或者单个xib的方式很可能不会再得到增强。
虽然Storyboard不能省去类中的所有代码,但是会让类中的代码量大大减少,除了可能存在部分控件状态改变的功能,其他整个类中不会再有与界面相关的代码。比如上面我模拟Storyboard开发的那个页面所对应的类中,只有按钮点击事件和tableView数据源和代理方法了,代码的量少,非常清晰。
5.3 大部分功能可以直接在图形化界面修改,更加面向对象
每个界面中可以清楚的看到此页面含有多少个对象(可能还有部分控件需要代码创建),选中每一个对象可以在右边的属性框中目的明确的修改各种属性,图形页面tbv下面的水平或垂直的bool选项。类似于 self.tableView.showsHorizontalScrollIndicator = NO;
这样的代码,在图形化界面中就对应一个勾,更加便于管理。
5.4 后期维护方便
如果现在有一个需求需要修改,可以通过手机app上指定的某个页面来到Storyboard中根据这个流程图中找到需要修改的页面进行修改。
假设是中间灰色的那个页面需要改。则先选中这个控制器然后在右边的属性列表找到所对应的类
然后点击图中箭头所指的按钮就可以直接定位到这个类。直接省去了繁琐的查找和搜索步骤直奔主题。
如果要修改一个自定义的Cell只需要在Storyboard中点击这个cell,即可在右边的Custom Class中看到这个自定义Cell所对应的类,可以直接定位过去。 相对于右边的图纯手码时在找这个截图中找这个Cell的类效率要快N倍。
5.5 产生冲突时的解决方案
在多人开发时,在同一个Storyboard内的同一个控制器内添加或修改控件时可能会产生冲突,一般情况下只要不是两个控件的frame完全相同就不会产生冲突,一旦产生冲突,冲突的提示会出现在图形化界面解析的XML文件中。可能会出现两个控件共同堆在同一个节点内产生冲突,解决的方法是在XML格式的文件中找到这两个控件并分离成两个不同的节点。
如果对同一个控件都修改了约束,约束的冲突可能会直接导致storyboard无法打开图形化界面,只能使用XML格式打开修改约束,这点比较麻烦,但也完全是可以解决的。日常开发中几乎不会出现两个人同时改同一个Storyboard中的同一个控制器的同一个控件的同一个属性的可能。
其实最根本的解决方法就是两种:
1.分多个storyboard开发,假设有商家模块,拜访模块,联系人模块。每一个模块对应一个故事发展的顺序,进而对应一个storyboard。每个人只需要修改自己所负责的storyboard,连两个人同时改同一个Storyboard的基本不可能出现。
2.每当业务的需求需要你修改别人所管理的模块内的IB时,可以提前和同事说一声,并且修改完成后再让他pull一下。这种做法在纯手码的开发中也是完全适用的,这一点是最科学的避免冲突的方法。
5.6 反对IB-Storyboard开发的人对这种开发模式的误区
原因一
大多为非常熟悉纯手码的老程序员,第一他们觉得纯手码来的最习惯,第二觉得纯手码最安全,第三有点排斥新的功能觉得不可靠而且再学起来比较费劲。其实Storyboard上手起来并不难,而且没有纯代码最安全这么一说,纯代码某些很小的改变产生的错误你犯了之后混在代码中找不到也是较为危险的。
原因二
他们不知道怎么把一个项目拆分成多个storyboard开发,他们以为一个项目只允许创建一个Main.storyboard。觉得自己的项目复杂可能会把几百个控制器塞在一个storyboard中开发,太难找了。其实完全可以拆分成多个Storyboard开发并且在一个主控制器的类中使用代码将多个Storyboard联系起来。
原因三
他们觉得用Storyboard的话又封装了一层,执行效率比较差。真相是因为相对于单个xib来说,StoryBoard文件往往更大,加载速度也相应变慢。但是其实随着现在设备的更新换代,在iPhone4都难觅的今天,这点性能上的差距几乎可以忽略了。而再之后的设备,不论读取还是解析,只会越来越快。所以性能上的问题完全是没有担心的必要的。在Xcode5之后,StoryBoard已经成为新建项目的默认配置,这也代表了Apple对开发者的建议和未来的方向。很多事情苹果其实已经为你考虑好了,给了你最佳的方案。
6. 对项目中使用IB开发的可行性分析
6.1 扩展性
首先使用IB开发会让项目的结构更加清晰,并且相对于纯手码更加容易维护,和在原来的基础上增加新的功能完成进一步的扩展。
6.2 关于冲突
因为现在此项目的iOS团队只有3人,并且之后的开发维护人员预计也不会超过5人。这样的团队,分配好没人所负责的模块后,出现冲突的概率微乎其微。在加上都是在坐在附近,就算是有大的可能出现冲突的隐患也可以直接当面交流提前说清。所以可以暂时忽略代码中出现冲突无法解决这种可能性。
6.3 开发模式自由
使用了Storyboard使得某些开发步骤变得简单,但是并不代表不允许使用手码开发。在以IB开发为主要的开发模式进行开发时,如果遇见特殊功能经讨论确实不适合使用Storyboard开发时,也完全可以针对此功能使用手码开发,这点是完全自由的。也就是说,几乎所有的页面创建都是在Storyboard中,类中的代码只有业务逻辑和代理方法了,如果再次之外还有关于页面的代码那就是核心功能了。让代码更加清晰。