从代码的整洁度上就可以看出一个程序员的实力,规范其实就是让你养成一种良好习惯的标杆,在此面前我们应该顺从。本篇我们以OC为例,统计了一些在编写程序中需要注意的事项,共有20条,当然还有更多的规范,此处只是做个示例。
- 单页代码最好控制在800行以内,每个方法最好不要超过100行,过多建议对代码进行重构
- 相同的逻辑方法定义避免在多个地方出现,尽量将公用的类、方法抽取出来
- 删除未被使用的代码,不要大片注释未被使用的代码,确定代码不会使用,请及时删除
- 对其他项目中copy过来的代码,根据具体需要更新代码风格,及时删除未被使用的代码
- 项目中所有Group或者文件名称(图片名字等),不要使用汉字命名,尽量使用英文命名,国内特有名词可以使用拼音。
- 项目中所有Group都需要在项目目录中存在一个真实的目录,Group中的文件与真实目录中文件一一对应。
- 请在项目中写必要代码的注释,请多使用 #pragma mark - Mark Name 对方法进行分组 。如:
#pragma mark - **********View lifeCycle******
- 所有类名称以项目工程开头命名,如:“JS”(简书)。针对不同视图控制器,在末尾添加后缀,如: UIButton 后缀添加“Button"或大家皆知的简写,NSArray的变量命名为xxxArray等。
类、方法、属性等命名,做到见名知意,采用驼峰式命名规则。 - 根据资源类型或者所属业务逻辑对项目资源进行分组,使得整个项目结构清晰明了;整个项目保持一种代码书写风格。
- 避免在程序中直接出现常数,使用超过一次的应以宏定义的形式来替代。常数的宏定义应与它实际使用时的类型相一致。如以3.0来定义浮点类型,用3表示整型。 常量的命名应当能够表达出它的用途,并且用大写字母表示。例如:
#define PI 3.1415926
- 当使用条件语句编码时,不要嵌套if语句,多个返回语句也是OK。
- (void)testMethod {
if (![testSome boolValue]) {// 不合适就返回,下面做处理
return;
}
//Do something important
}
- 当方法通过引用来返回一个错误参数,判断返回值而不是错误变量。在成功的情况下,有些Apple的APIs记录垃圾值(garbage values)到错误参数(如果non-NULL),那么判断错误值会导致false负值和crash。
NSError *error;
if (![self trySomethingWithError:&error]) {
// Handle Error
}
- 当参数过长时,每个参数占用一行,以冒号对齐。如:
- (void)aboutFisrtNumber:(NSString *)oneStr
withNextNumber:(NSString *)twoStr
withLastNumber:(NSString *)threeStr{
// do something
}
- 一行很长的代码应该分成两行代码,下一行用两个空格隔开
self.productsRequest = [[JSProductsRequest alloc]
initWithProductIdentifiers:productIdentifiers];
- 删除多余的空行,所有方法与方法之间空1行,所有代码块之间空1行。变量声明后需要空1行,如果需要分类区别,各类别之间空1行。条件、循环,选择语句,整个语句结束,需要空1行。最后一个括弧之前不空行。注释与代码之间不空行。
#pragma 与方法之间空1行
每行代码最多不得超过100个字。
如果类声明中包含多个protocol,每个protocol占用一行,缩进2个字符如:
3211.png图片命名:采用单词全拼,或者大家公认无岐义的缩写(比如:nav,bg,btn等);采用“模块+功能”命名法,模块分为公共模块、私有模块。公共模块主要包括统一的背景,导航条,标签,公共的按钮背景,公共的默认图等等;私有模块主要根据app的业务;功能模块划分,比如用户中心,消息中心等。建议背景图采用以bg作前缀,按钮背景采用btn作前缀。如:account_gray_qq@2x.png,addpic_icon_menu_disable@2x.png等。
着手一个新项目条理
在着手一个项目前先读文档(如果有文档的话)。尽管读了文档你不一定知道每一个代码的细节,但是如果你了解那个问题的话,你一定知道怎么写可以写出一个满足文档的内容。这个时候大脑里面就可以有个框架,先猜一猜,然后看代码,事半功倍。找不到好的文档,就看他的测试用例,也是有一样的功效的。因为测试都是从文档出发编写的,而不是从代码出发编写的。找不到文档和测试用例?那就直接Gank吧。
读代码要层次化、带着问题去阅读。首先整体了解这个软件是干什么?解决什么问题?包含哪些大的模块,各个模块的作用是什么,各个模块的调用关系怎么样?然后对于每一个模块,这个模块是干什么的?为什么要有这个模块?这个模块怎么实现的?最后细化到每一个包,每一个类,每一个函数方法。从上到下,一一击破每一个问题,认真去思考他这样设计、写代码的好处,因为好的软件都会满足这种从抽象->具体的原则的。
在开始读具体代码前定位好所有要读的文件,知道他们的位置和名字,设计良好的工程光看工程的目录结构和文件名就能知道个大概功能了。事实上阅读代码的难易程度70%取决于代码书写的规范程度,写乱掉的代码,大师也读不懂。之后根据你对目录结构的理解确定文件阅读的顺序(我反正都是从main函数开始读的)。你最好对设计模式有一定了解,否则你读面向对象的code时会经常无法理解code为啥要弄得这么层层嵌套。阅读代码一个最重要的提升水平的地方就是理解好的代码如何合理使用设计模式。基本的阅读起点都会选择main函数或者类的构造函数。然后把自己想象成cpu执行程序那样去阅读你的代码。遇到需要跳转函数时,不要急于跳转,以了解函数功能和输入输出为目标,读代码最忌讳的是不抓结构抓细节,只见树木不见森林,比起某个函数具体功能来说对结构的全局把握更重要。功能了解清楚后继续跳回来(这里就可以区分代码写的优不优秀,优秀的代码光看函数名字就知道功能,连跳转都不用)。结构弄清楚了,知道程序怎么跑了,source code的精华你已经读了60%了,之后根据需要再对具体函数深入分析,到这里整个代码已经被你扒光了,没什么神秘了。
阅读代码有两种模式:top-down 和 bottom-up。Top-down 模式,就是先设定一个 use case,比如说打开一个文件。然后静态跟着代码看,或者用 debugger 跟着看。每次出现函数调用的时候,把函数的执行层次纪录下来。大致如下:
func1( )
func2( )
func( )
func3( )
这种图表很随意,你可以根据自己的需要增加信息,可以把重要的「实际参数」一直标下来,画函数调用图,然后标注每个函数在干什么。不过这个图无法清楚地表明一个变量的轨迹,需要另外的图来标示变量的变化轨迹。要是想提高阅读代码的速度,归根结底要多读多写。熟悉程序的基本构成单元(例如循环、分支)的常见写法,各种lib, api的调用方式。这样阅读深层次代码不用再回头查形式参数到底指什么。这个图的基本作用是防止在阅读深层次代码时忘记总体执行层次。Top-down 模式进行到一定层次,往往会发现虽然图画了出来,但还是无法了解程序在干什么。这时需要转入 bottom-up 模式,一直深入到最底层,给能了解作用的底层函数一个一个的写文档。当然这时的文档是完全底层的观点。bottom-up的阅读方法,有时候会一头扎进去,出不来了。这种方式适合读一些比较优秀的开源项目的代码,也会很好地提高内功。然后就是不断在两个模式之间转换,不断的细化两种模式的理解。
最后,对于OC工程可以去GitHub找UIViewController-Swizzled这个库,拉下来放到项目里,他有什么用呢?他可以把每个页面的类名打出来。而且有层次结构,也就是说你只需要打开项目点点点,就知道这个App运行的顺序了。
iOS开发的细节及全局观
"好代码是廉价的",这句话没有歧义。中国的语言博大精深,其实这句话的真实含义是,优秀的代码使用起来毫不费力。通常我们对好代码的定义是优雅的使用各种设计模式,兼顾各种情况(异常或是正常),有效而且合理的使用优化算法等。很好,这在开发中帮我们做了很多事,这也是在开发中值得发扬的。但是,这难免的会增加实现的复杂性,如果对某些技巧认识不清极有可能成为一种开发的阻碍。实际上,在日常的开发中,我们大多是为了实现功能,很多的都是在写“廉价的代码”,以功能优先,先实现功能然后再根据需要在后期进行优化,这没什么不好。
其中一个误区是,我们需要从逻辑着手而不是功能,这样固然很好,但却会影响开发的效率。好的程序员和伟大的程序员之间的区别就在于伟大的程序员理解他们的模式,让代码廉价。当模式能够给你带来好处,而且为你省时时才去使用它们,如果不是这样就不要使用它们。当框架能够帮你提高开发速度时才使用它们,
在必要的时候重构,不要做一些超前性的开发。这些只是针对于日常开发,编写SDK或框架是另一套逻辑,总之就是不要抱残守缺,固守一种形态,学会因地制宜。
一个不好的现实是大多数程序员都是业务性程序员,每天重复着一样的工作,写着功能不同但形式上是一样的代码,这就是普通程序员的宿命,因此上面才会为了快速构建而选择“廉价的代码”。但是,这不是有进取精神的程序员所想要的,所以我们才会有进步,即使是一个小工也要像专家一样思考。
那么,所谓的专家们,在看一个项目时是如何思考的呢,我们下面做一些分析。
优秀的开发者会从架构的视角来看问题,一般而言,软件系统的架构(Architecture)有两个要素:
它是一个软件系统从整体到部分的最高层次的划分。
一个系统通常是由元件组成的,而这些元件如何形成、相互之间如何发生作用,则是关于这个系统本身结构的重要信息。
架构是一个约定,一个规则,一个大家都懂得遵守的共识。需要强调的是“架构因未来而存在”。架构的最终体现是一个软件,是模块化,简洁,可维护,可任意替换,人性化设计,可以把它全部打碎了重新从一个模型自由的再去组装成另一个模型。是高内聚,低耦合,既可以作为一个完整的可交付模块,也可以“打碎”重组。架构需要考虑的是扩展性,安全和性能,如此才算是合理的架构。
在构建项目时,不管采用什么方法,全局观、高度的代码审美能力、灵活使用各种设计模式一定都是贯穿其中的。首先,搞清楚业务逻辑,这决定了你的架构是否足够易用。另外,传的参数越少,耦合度相对而言就越小,你替换模块或者升级模块所花的的代价就越小。搞清楚业务之间的依赖关系,建立好模块交流规范并设计模块,关键在于建立一套统一的交流规范。推演预测一下未来可能的走向,必要时添加新的模块,记录更多的基础数据以备未来之需。软件是有生命的,多一点考虑便会多一分健壮。
好的架构需要下面几点:
- 代码整齐,分类明确,没有common,没有core
- 不用文档,或很少文档,就能让业务方上手
- 思路和方法要统一,尽量不要多元
- 没有横向依赖,万不得已不出现跨层访问
- 对业务方该限制的地方有限制,该灵活的地方要给业务方创造灵活实现的条件
- 易测试,易拓展
- 保持一定量的超前性
- 接口少,接口参数少
- 高性能