在互联网上关于 Interface Builder 的争吵每天都在发生,用和不用大家都有一大堆的理由。最近看了这篇文章,很多地方和作者有共鸣,结合自己的一些经历,就有了你现在所看到的东西,你可以把它当成前者的中文版。

一年前我开始做 iOS 开发,看的是Stanford 的 CS 193P。老头子推荐新手用 Storyboard 来做开发,因为它是可视化的,不太需要了解代码层的东西就能拖出界面,各种配置项可以通过勾选搞定,省去很多代码,相当傻瓜,此外 Storyboard 也让人对应用程序的活动流程一目了然。我对这种拖拽式的编程方式很不习惯:这不是代码出奇迹的节奏啊!

我开始做实际的项目。看了几个开源项目的代码后,我知道旧时代有个xib格式的文件。这货是 Interface Builder 的产物,现在我们称他们为 NIB。用法和 Storyboard 差不多,可视化拖拽、配置。Storyboard 比较新,业界用的人不多,于是我很纠结,到底是听老头子的话用新东西,还是随大流试试单独的 NIB?初生牛犊不怕虎,反正没怎么做过 iOS 开发,就按课上说的来吧,我们团队用 Storyboard 拖 UI。一个月后,我提议弃用 Interface Builder,不用任何 NIB(包括 Storyboard)。直到现在只要是在我控制范围内,我都没再碰过任何 NIB,我更愿意用代码来生成。

不用 Interface Builder 的理由很多,对我来说主要有一下几点:

1. 多人协作

从项目管理的角度来讲 NIB 就不应该被使用。你能保证自己从来不会在合并 NIB 时出现冲突吗?在一个稍有规模,多开发者的项目里,合并 NIB 简直就是梦魇。特别是多人共用一个 Storyboard 时,开发者将花费很多时间和精力去解决冲突,而不是去做比这更有意义的事。

当然,如果最终合并结果正确可信,那么很多同学还是可以忍受的。然而,合并毕竟是会出问题的,尤其是用 Git 自动合并。这些问题直到运行时才会出现!倘使测试力度不够,这就是潜在的隐患。此外,我们知道 NIB 是人不可读的,也就是说,对它做版本控制几乎没有意义。你没法从 diff 看出来半点名堂。倘使你使用的不是 NIB,而是一行一行的 Objective-C 代码,那么结果会好很多。

2 选择显式而非隐式

我喜欢用代码来完成各种东西,这样你打开一个 view 或者一个 view controller,就能看到所有东西。否则,看你代码的这位同学还得去找相应的 NIB。

NIB 同样也是滋生 bug 的温床,很多时候你调试了半天才发现,某个 bug 并不是出在自己的代码里,而是在 Interface Builder 的某个小角落里自己忘记给某个选项打上 √。如果所有的组件都由代码生成,那么在调试时就简单得多,你只要专注于和 View 有关的代码就快好了。选择显式地在代码里写 view,可以让你对 view 有强大的控制力。从初始化到布局、绘制你都能插手,在代码里你清楚地知道某个 view 的各个属性会是多少,而非交由 Interface Builder 来管理,这样虽然看上去代码行数多了,但它帮你减少了 bug 数量,节省了 debug 时间。

3 耦合

用 Interface Builder 去创建可复用的 view 会是一件很蛋疼的事。首先你需要拖拽出各种各样的组件,然后给每个组件设置属性,接着你要把 outlet 连接到要用到的代码块……某一次,你忘记连 outlet,然后你的程序就在 runtime crash 了。看,你又弄出了一堆 bug。对于各种零碎的 view 我更喜欢为他们写类,然后在里面实现各种我想要的东西,在需要用到这些 view 的时候生成对象就是了。如果我有什么错误,编译器大哥还能帮我检查。

使用 NIB 让我提心吊胆,它让程序变得不那么紧凑。很多需要内聚的东西,被分了出去。从实际的开发体验来讲就是东一块,西一块,切来切去我都觉得烦。一旦当你定制的 view 越来越多,NIB 就增多,然后呵呵。

4 布局

我承认自己几乎没在 Interface Builder 用过各种 layout(包括 auto-layout)。我不清楚用 NIB 做 layout 是否困难。但我知道重写UIViewlayoutSubviews让布局变得很简单。所有子元素的布局只要在这里设置就行了。需要重新布局时,调一下setNeedsLayout就行。不用关心什么 Interface Builder 里各种 layout 概念,不用把布局代码分地方写(降低耦合)。只要稍加判断,让同一个 view 适应 iPhone 和 iPad 不是什么难事。给 iPad 和 iPhone 分别提供 NIB 这种事简直不能忍。

5 本地化

当 IB 遇到本地化会发生什么呢?我屮艸芔茻!只要涉及本地化的 NIB,都要你去投时间和体力做啊。点鼠标啊,设置啊,纯体力活!如果用代码,字符串用NSLocalizedString(@"Localizable String", @"Comment"),然后在资源文件里翻译一下,轻轻松松。

6 小结

Interface Builder 的初衷可能是希望帮助开发者节省写界面的时间和精力。可视化,表现层和数据分离都是很好的思想。但它在目前还不让人满意。它让多人协作变得困难,诱导拙劣的实践,降低可复用性,让你开发变慢……

我如果能不用 IB,就不用,作为一名程序员更应该用代码说话。从装逼角度来讲,这样才显得高端大气上档次不是吗?