结合个人iPhone开发经历,提几点iPhone UI开发方面的建议。
建议1 尽量使用系统控件
系统控件可以使得用户容易上手,但在iPhone开发中还有很多人习惯使用checkbox而不是UISwitch,使用combobox而不是使用UIPickerView。究其原因可能有两点:一是从其他Windows或者Android系统转到iPhone开发的残留,二是因为跨平台开发中为了减少设计和资源的工作而趋同设计。不过这样的设计往往造成自定义控件的开发投入,质量上也往往无法和系统控件相媲美。
建议2 合理抽象
UI代码是很容易重复写的代码,很多时候就会造成代码效率的错局,让人有一种高效工作的错觉。其实很多代码是完全重复或者结构重复的,通过适当的抽象就可以进行消除和避免。比如在一个应用中,不同地方所需要的内嵌网页浏览器,这些地方往往都有一些共通的行为。比如加载的时候会显示加载进度并在状态栏显示网络状态图标,在加载完毕后隐藏进度和网络状态显示。如果单独在不同Controller中实现不仅不合理,而且容易造成大量代码重复以至于后来的维护噩梦。通过合理抽象,抽取一个基类后就可以封装这块的行为,实现相同逻辑代码的复用。
建议3 优先使用组合
UI中很多部分应该像积木,可以随意拼接组合。比如下图的用户信息显示部分可以由诸如UIImageView,UILabel等几个基本控件拼接而成,而这种显示在一个项目中会通常在多个界面中显示。面对这种的问题,参考建议2后可能就会想着抽象一个基类用来处理用户信息显示相关的逻辑和界面。所有有这需求的界面都可以继承自这个基类。这种抽象是解决了逻辑和界面重复实现的问题,但另一方面却引入了高耦合的继承。如果有些界面因为功能原因更会迫切继承一个其他基类,比如建议2中提到的处理网页加载的基类,由于Objective-C无法支持多重继承,从而被迫进行部分代码的copy&paste。所以在抽象的时候就应该格外珍惜基类的抽象的使用,不断利用Liskov原则进行继承合理性的检查和确认,同时把握“优先使用组合”的原则,通过基本控件的组合制作一些应用相关的组合,比如显示用户信息的,这样其他需要的节目就可以利用组合来复用这部分代码,从而避免继承,也其他更合理的继承保留可能。
建议4 UI和逻辑的分开
这是很重要的一点,iPhone SDK给开发者提供了一个很好的基础来实现UI和逻辑的分开,所以实现的过程中务必遵照一些Apple的指导文档,而避免在UI中揉合着大量逻辑代码。要真这样的话不仅对不起Apple工程师在这方面的努力,更是给自己增加无尽的麻烦。
建议5 充分利用IB。
曾经遇到这样的一个同事,九几年开始做MFC开始,最初也很希望使用STL库,不过在一次项目中发现了STL的内存泄露问题后就开发摒弃STL,以至到现在也不允许自己和属下在项目开发中使用STL。这真是一朝被蛇咬,十年怕井绳。在使用Xcode进行iPhone开发的过程中同样有这样的一些人。他们很早就开始接触和使用IB,但使用过程中发现很多IB的问题和不便,甚至有一些在实际项目中无法忍受,以至于到现在还一直抵触IB。目前,虽不敢说IB已经很完美,但是它对开发效率的提高所起的作用是毋庸置疑的。
建议6 不要低估了Apple工程师
在开发的过程中经常会发现一些比较奇怪的问题,这时候通常就怀疑是不是Apple的bug,于是乎就开始寻找一些特殊处理进行规避并逐渐认定这就是Apple的问题。一旦有过这样的经历后,以后遇到类似的问题就会首选自己发现的那些特殊处理,而逐渐偏离了开发的正道。举个自己亲身经历的例子,一次为了改变UITableViewCell的颜色,开始时直接改变cell的backgroundColor,但发现搞不定,一番搜索后发现改变cell的ContenView的backgroundColor就OK了,不过一旦显示accessoryView就露馅了。于是乎干的彻底点,直接自定义一个UITableViewCell,并用一个UIImageView做背景,现在终于可以“为所欲为”了。不过回想下,怎么简单的一个问题如此大动干戈,真是不值当,所以心里会暗暗骂下Apple的工程师,怎么就不让cell的backgroundColor起作用呢?这么明显的bug!以至于以后的一段时间我就习惯用那“土办法”,而且是屡试不爽。突然有天在stackoverflow上看到一个类似问题的讨论,原来这种问题可以通过重写-tableView:willDisplayCell:forRowAtIndexPath:的委托方法实现。想想之前骂过的话以及走过的弯路,只能感叹自己掌握不深入。有了这样的经历后在遇到类似的问题我会先怀疑使用合理,而不是轻易下结论。
以上