IOS中的编码规范

 

1.指导原则

【原则1-1】首先是为人编写程序,其次才是计算机。
 说明:这是软件开发的基本要点,软件的生命周期贯穿产品的开发、测试、生产、用户使用、版本升级和后期维护等长期过程,只有易读、易维护的软件代码才具备生命力。
【原则1-2】保持代码的简明清晰,避免过度的编程技巧。
 说明:简单是最美。保持代码的简单化是软件工程化的基本要求。不要过度追求技巧,不然会下降程序的可读性。
【原则1-3】编程时首先达到正确性,其次考虑效率。
 说明:编程首先考虑的是知足正确性、健壮性、可维护性、可移植性等质量因素,最后才考虑程序的效率和资源占用。
【原则1-4】编写代码时要考虑到代码的可测试性。
 说明:不能够测试的代码是没法保障质量的,开发人员要牢记这一点来设计、编码。实现设计功能的同时,要提供能够测试、验证的方法。
【原则1-5】函数(方法)是为一特定功能而编写,不是万能工具箱。
 说明:方法是一个处理单元,是有特定功能的,因此应该很好地规划方法,不能是全部东西都放在一个方法里实现

 

2.布局

        程序布局的目的是显示出程序良好的逻辑结构,提升程序的准确性、连续性、可读性、可维护性。更重要的是,统一的程序布局和编程风格,有助于提升整个项目的开发质量,提升开发效率,下降开发成本。同时,对于普通程序员来讲,养成良好的编程习惯有助于提升本身的编程水平,提升编程效率。所以,统一的、良好的程序布局和编程风格不只仅是我的主观美学上的或是形式上的问题,并且会涉及到产品质量,涉及到我的编程能力的提升,必须引发你们重视。html

2.1.文件布局

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

说明:如下内容若是某些节不须要,能够忽略。可是其它节要保持该次序。 程序员

头文件布局:编程

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

正例:app

/***************************************************************************函数

 *                                文件引用工具

 ***************************************************************************/ 布局

/***************************************************************************测试

 *                                 类引用编码

 ***************************************************************************/

 

/***************************************************************************

 *                                 宏定义

 ***************************************************************************/

/***************************************************************************

 *                                 常量

 ***************************************************************************/ 

/***************************************************************************

 *                                类型定义

 ***************************************************************************/ 

/ ***************************************************************************

 *                                 类定义

 ***************************************************************************/

【规则2-1-2】遵循统一的布局顺序来书写实现文件。


说明:
如下内容若是某些节不须要,能够忽略。可是其它节要保持该次序。 

实现文件布局:

文件头(参见“注释”一节)

#import (依次为标准库头文件、非标准库头文件)

文件内部使用的宏

常量定义

文件内部使用的数据类型

全局变量

本地变量(即静态全局变量)

类的实现

 

正例:

/***************************************************************************

 *                                文件引用

 ***************************************************************************/ 

/***************************************************************************

 *                                 宏定义

 ***************************************************************************/

/***************************************************************************

 *                                 常量

 ***************************************************************************/ 

/***************************************************************************

 *                                类型定义

 ***************************************************************************/

/***************************************************************************

 *                                全局变量

 ***************************************************************************/

/***************************************************************************

 *                                 原型

 ***************************************************************************/

/ ***************************************************************************

 *                                类特性

 ***************************************************************************/

@implementation ClassName 

/ ***************************************************************************

 *                                类的实现

 ***************************************************************************/

 

2.2类结构布局

使用#pragma mark –来分类方法
#pragma mark – Getters and Setters

#pragma mark – Life Cycle

#pragma mark - Events

#pragma mark – Private Methods

#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate

#pragma mark - Custom Delegates

 

2.2.1布局中的空格

每一个方法或者功能块之间为告终构清晰,应当有且只有一行空格。

#interface SomeClass:NSObject

@property (noatomic, strong) UIView *aView

-(void)someMethod;

@end

@implementation SomeClass

- (void)setAView:(NSInteger )aview {

}

-(void)someMethod {

}

@end

2.2.2关于布局中的Private Methods块,正常状况下ViewController里面不该该写

不是delegate方法的,不是event response方法的,不是life cycle方法的,就是private method了。对的,正常状况下ViewController里面通常是不会存在private methods的,这个private methods通常是用于日期换算、图片裁剪啥的这种小功能。这种小功能要么把它写成一个category,要么把他作成一个模块,哪怕这个模块只有一个函数也行。

ViewController基本上是大部分业务的载体,自己代码已经至关复杂,因此跟业务关联不大的东西能不放在ViewController里面就不要放。另一点,这个private method的功能这时候只是你用获得,可是未来说不定别的地方也会用到,一开始就独立出来,有利于未来的代码复用。

2.2.3属性初始化放哪最好?建议:Getter和Setter

我看到不少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的地方都能享受到,仍是不错的。 

3.表达式

3.1 if语句

表达式大括号和其余大括号(if/else/switch/while 等.)老是在同一行语句打开但在新行中关闭。若是没有else 而且括号内只有一行语句,能够和if语句同行,而且不须要括号。

if (user.isHappy) {
  //Do something
} else {
  //Do something else
}

if (somethingIsBad) return something;

3.2switch语句

大括号在case语句中并非必须的,除非编译器强制要求。当一个case语句包含多行代码时,大括号应该加上。

switch (condition) {
  case 1:
    // ...
    break;
  case 2: {
    // ...
    // Multi-line example using braces
    break;
  }
  case 3:
    // ...
    break;
  default: 
    // ...
    break;
}

当在switch使用枚举类型时,'default'是不须要的。例如:

RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;
switch (menuType) {
  case RWTLeftMenuTopItemMain:
    // ...
    break;
  case RWTLeftMenuTopItemShows:
    // ...
    break;
  case RWTLeftMenuTopItemSchedule:
    // ...
    break;
}

4.注释

代码中尽可能少注释,让代码能自我描述。不过当须要注释的时候,能须要清除的解释某个代码块的含义和做用。注释应当保持最新,若是没必要要请删除。

4.代码规范要点

不要在viewDidLoad里面初始化你的view而后再add,这样代码就很难看。在viewDidload里面只作addSubview的事情,而后在viewWillAppear里面作布局的事情最后在viewDidAppear里面作Notification的监听之类的事情。至于属性的初始化,则交给getter去作。

#pragma mark - life cycle

- (void)viewDidLoad {

    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:self.firstTableView];
    [self.view addSubview:self.secondTableView];
    [self.view addSubview:self.firstFilterLabel];
    [self.view addSubview:self.secondFilterLabel];
    [self.view addSubview:self.cleanButton];
    [self.view addSubview:self.originImageView];
    [self.view addSubview:self.processedImageView];
    [self.view addSubview:self.activityIndicator];
    [self.view addSubview:self.takeImageButton];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    CGFloat width = (self.view.width - 30) / 2.0f;
    self.originImageView.size = CGSizeMake(width, width);
    [self.originImageView topInContainer:70 shouldResize:NO];
    [self.originImageView leftInContainer:10 shouldResize:NO];
self.processedImageView.size
= CGSizeMake(width, width); [self.processedImageView right:10 FromView:self.originImageView]; [self.processedImageView topEqualToView:self.originImageView]; CGFloat labelWidth = self.view.width - 100; self.firstFilterLabel.size = CGSizeMake(labelWidth, 20); [self.firstFilterLabel leftInContainer:10 shouldResize:NO]; [self.firstFilterLabel top:10 FromView:self.originImageView]; ... ... }

这样即使在属性很是多的状况下,仍是可以保持代码整齐,view的初始化都交给getter去作了。总之就是尽可能不要出现如下的状况: 

- (void)viewDidLoad {
    [super viewDidLoad];
    self.textLabel = [[UILabel alloc] init];
    self.textLabel.textColor = [UIColor blackColor];
    self.textLabel ... ...
    self.textLabel ... ...
    self.textLabel ... ...
    [self.view addSubview:self.textLabel];
}
相关文章
相关标签/搜索