iOS架构师之路:制定代码规范真珠美学

前言

先吹个牛,我打心眼自认为自己是喜欢对集体项目标代码质料负责的人,对于思考什么写出高质地可读性的代码我是乐此不彼。在此以前我写过两篇关于代码命名规范和代码编写规范的小说,《iOS架构师之路:iOS开发(OC)中的命名规范》《iOS架构师之路:IOS项目中的编码规范》,您假如心态很好,就去探望吧,假如低于很好,这不指出您看,怕您心里骂娘,因为现在看,感觉温馨写的不太认真,有好多上边可以写的更仔细,恩,我主宰给自己帖贴金,不可以这样说自己:其实这半年小哥我在代码规范地点的文化又见涨不少,所以看往日定制的科班不爽,作为架构师保持谦虚,通过不停学习,不断自我修正,对代码有一些洁癖是该有的丰采(潜台词其实我想说自己有)。制定项目标代码规范对架构师的重大,就像要你生个娃一如既往,责任重大,万一生出来缺胳膊少腿,娶不到孙女,你将来就是伺候她生平,给他当牛做马,他也不必然会念你的好。

论代码规范的重中之重

  • 1.架构师要为整个项目技术方向的前行负责,所以制定一个出色的代码规范,让开发工程师遵从,有利于项目朝着您预知的取向提升。比如当您向利用AOP技术实现日志效率时,就需要规定部分办法命名。
  • 2.等同的代码规范,有利于代码reveiw工作。假若每个工程师写的代码风格不等同,review代码的同事,阅读起来肯定不顺畅。
  • 3.渴求工程师遵照代码规范写出一致的代码,就不怕她跳槽。这行本来就浮躁,流动性大,倘使工程师写的代码风格唯有她协调能看懂,这东西他跳槽,新人是很难继续保障这有的代码的,得不偿失。

作育代码洁癖

给我们推荐一本关于代码规范的名篇,第一本:《禅与 Objective-C
编程艺术(Zen and the Art of the Objective-C Craftsmanship
粤语翻译)》
(简称:Zen),这本书开源社区的大牛,无偿进献出来的,该书给大家介绍许多写代码的不错姿势,并解释为啥使用这些姿势体验更好。看完这本书应当明了咋样写出优雅、高可读性并且可靠的代码了。

自己引进的代码规范

《The Objective-C Style Guide used by The New York
Times》
(简称:New
York,该专业也有粤语版),《New
York》是自我相比欣赏的编码规范风格,它是《Zen》的编码思想一个很好的实践。

有关《Zen》、《New York》代码规范的补充

1.iOS切图文件的命名规范

这有些专业或者是很有经历的计划性提供,也有可能是我们开发人员提供,了解总是没有害处的。

咱俩的命名规则的中央思维是把公文名分成三部分,第一部分是图表的逻辑归属分类,第二有的是图形的表现内容,第三局部是图片的情节的项目,有些图片还会有第四片段,表示图片表现的事态。首先有多少个规则是:

  • 用英文命名,不用拼音
  • 每一片段用下划线分隔
  • 图形名中两倍图在名字最后要加@2x,三倍图在名字最终要加@3x

万能公式

image_naming_guideline.png

2.类的布局

次第布局的目的是显得出程序可以的逻辑结构,提高程序的准头、连续性、可读性、可维护性。更关键的是,统一的次第布局和编程风格,有助于增强总体项目标付出质地,提升支付功能,降低开发成本。同时,对于一般程序员来说,养成非凡的编程习惯有助于增高自己的编程水平,提升编程效能。因而,统一的、优秀的次第布局和编程风格不仅仅是私有主观美学上的或者格局上的题材,而且会波及到产质料地,涉及到村办编程能力的增进,必须引起我们尊重。

2.1.文书布局

【规则2-1-1】坚守统一的布局顺序来书写头文件。

说明:以下内容假若某些节不需要,可以忽略。然而任何节要保持该次序。**
**
头文件布局:

文件头
#import (依次为标准库头文件、非标准库头文件)
全局宏
常量定义
全局数据类型
类定义

正例:

/***************************************************************************
 *                                文件引用
 ***************************************************************************/ 
/***************************************************************************
 *                                 类引用
 ***************************************************************************/

/***************************************************************************
 *                                 宏定义
 ***************************************************************************/
/***************************************************************************
 *                                 常量
 ***************************************************************************/ 
/***************************************************************************
 *                                类型定义
 ***************************************************************************/ 
/ ***************************************************************************
 *                                 类定义
 ***************************************************************************/

【规则2-1-2】遵守统一的布局顺序来书写实现文件。
说明:以下内容假如某些节不需要,可以忽略。不过任何节要保持该次序。
兑现文件布局:

文件头(参见“注释”一节)
#import (依次为标准库头文件、非标准库头文件)
文件内部使用的宏
常量定义
文件内部使用的数据类型
全局变量
本地变量(即静态全局变量)
类的实现

正例:

/***************************************************************************
 *                                文件引用
 ***************************************************************************/ 
/***************************************************************************
 *                                 宏定义
 ***************************************************************************/
/***************************************************************************
 *                                 常量
 ***************************************************************************/ 
/***************************************************************************
 *                                类型定义
 ***************************************************************************/
/***************************************************************************
 *                                全局变量
 ***************************************************************************/
/***************************************************************************
 *                                 原型
 ***************************************************************************/
/ ***************************************************************************
 *                                类特性
 ***************************************************************************/
/ ***************************************************************************
 *                                类的实现
 ***************************************************************************/
2.2类社团布局

使用#pragma mark –来分类方法

#pragma mark – Life Cycle

#pragma mark - Events

#pragma mark – Private Methods

#pragma mark - UITextFieldDelegate

#pragma mark - UITableViewDataSource

#pragma mark - UITableViewDelegate

#pragma mark - Custom Delegates

#pragma mark – Getters and Setters
2.3布局中的空格

各种方法或者功用块之间为了社团清晰,应当有且唯有一行空格。

@interface SomeClass:NSObject

@property (noatomic, strong) UIView *aView

- (void)someMethod;

@end

@implementation SomeClass

- (void)setAView:(NSInteger )aview {

}

- (void)someMethod {

}
@end
2.4关于布局中的Private Methods块,正常境况下ViewController里面不应该写

不是delegate方法的,不是event response方法的,不是life
cycle方法的,就是private
method了。对的,正常情形下ViewController里面一般是不会存在private
methods的,那些private
methods一般是用以日期换算、图片裁剪啥的这种小效能。这种小功效仍旧把它写成一个category,要么把他做成一个模块,哪怕这几个模块只有一个函数也行。
ViewController基本上是多数业务的载体,本身代码已经非凡复杂,所以跟工作关系不大的事物能不放在ViewController里面就毫无放。其它一些,那些private
method的效劳这时候只是你用取得,不过以后或许另外地点也会用到,一起先就独自出来,有利于未来的代码复用。

3.属性初叶化放哪最好?提出在Getter中初步化

自身看出不少APP,甚至自己企业的品种,很多支出工程师,初叶化属性的地点相比较随便,有单独添加一个开头化方法类似setupView的,有在init开头化的,各类场地都有,我其实挺崩溃的,首先先导化格局不雷同,其次也这样做特别有可能损坏了每个方法效果的单一性(每个方法只做一件事)。我相比较习惯一个目的的”私有”属性写在extension里面,然后这么些属性的先导化全部坐落getter里面做,在init和dealloc之外,是不会现出其他类似_property这样的写法的。就是这般:

@interface CustomObject()

@property (nonatomic, strong) UILabel *label;

@end

@implementation

#pragma mark - getters and setters

- (UILabel *)label {
    if (_label == nil) {
        _label = [[UILabel alloc] init];
        _label.text = @"1234";
        _label.font = [UIFont systemFontOfSize:12];
        ... ...
    }
    return _label;
}
@end
#pragma mark - life cycle

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.label];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.label.frame = CGRectMake(1, 2, 3, 4);
}

唐巧说他喜爱的做法是用_property这种,然后关于_property的伊始化通过[self setupProperty]这种做法去做。从刚刚位置的代码来看,就是要在viewDidLoad里面多调用一个setup方法而已,然后我引进的法门就是毫无多调一个setup方法,直接走getter。

啊,怎么说呢,其实两种做法都能完成需求。可是从另一个角度看,苹果之所以采纳让[self getProperty]self.property可以互相通用,那种做法已经很明朗地发挥了苹果的协助:希望每个property都是因此getter方法来获取。

早在2003年,Allen Holub就发了篇著作《Why getter and setter methods are
evil
》,自此之后,业界就对此爆发了各个争议,即便是从Java先导说的,可是发展到前面各种语言也出席了进来。然后尽管现在有关这多少个问题探究得少了,不过依旧属于没有定论的情事。setter的情事比较复杂,也不是本人这一节的显要,我这边如故关键说getter。大家从objc的计划性来看,苹果的设计者更加倾向于getter
is not evil。
认为getter is
evil的缘由有那么些之多,或大或小,随着争辩的拓展,我们逐步就聚焦到这样的一个原因:Getter和Setter提供了一个能让外部修改对象内部数据的不二法门,这是evil的,正常状态下,一个目的自己个人的变量应该是只有自己关注。

下一场我们回来iOS领域来,objc也一致面临了如此的题目,甚至更为严重:objc并从未像Java那么严峻的民用概念。但在其实工作中,大家不太会去操作头文件之中没有的变量,这是从规范上就被禁止的。

认为getter is not
evil的来由也得以聚焦到一个:低度的封装性。getter事实上是工厂方法,有了getter之后,业务逻辑可以更加注意于调用,而毋庸顾虑当前变量是否可用。我们可以想转手,假设一个ViewController有20个subview要进入view中,这20个subview的最先化代码是一定逃不掉的,放在哪个地方相比好?放在什么地方都比位居addsubview的地点好,我个人觉得最好的地点仍旧放在getter里面,结合单例格局之后,代码会非常利落,生产的地方和应用的地点拿到了很好的分别。
由此放到iOS来说,我或者觉得采用getter会相比好,因为evil的地点在iOS这边基本都制止了,not
evil的地方都能分享到,依然不错的。

4.Getters and Setters放在最底部

本身事先写代码一贯把Getters and Setters
放在implementation的最前方,前几日看大神casatwy说最好放在最后面,我认为更有道理。控制器可能会有丰硕多的view属性和任何属性,如若具有的getters
and
setters放在眼前,就会造成在implementation代码顶部有大量的开端化代码,这就导致重大的逻辑代码挪到背后去了,其旁人阅读代码是不太便宜的。

结尾

夜深人静,该睡了。欢迎收藏的
自己的博客