iOS 代码规范

基本原则:

清晰又简洁的代码当然是最好,但简洁不如清晰重要。不要使用单词的简写,除了非常常用的简写以外,尽量使用单词全称。API的名称不要有歧义,一看API就知道是以什么方式做了什么事情。

1、命名

类的命名:

大驼峰式命名:即每个单词的首字母采用大些字母。
使用能够反映类功能的名词短语。

DoneCourseListView

分类(类别)命名:

与类命名相同,此外需添加要扩展的类名和“+”

NSString+MTValidate

方法命名:

小驼峰式命名:首字母小写,之后每个单词首字母都大写
方法名使用动词短语。

- (void)setPostValue:(int)value

方法参数命名:

首字母小写,之后每个单词首字母都大写
具有足够的说明性,不需要添加类型前缀

- (void)sendUserInfo:(NSDictionary*)userInfo

宏命名:

全部大写,单词间用 _ 分隔。[不带参数]

#define THIS_IS_AN_MACRO @"THIS_IS_AN_MACRO"

以字母 k 开头,后面遵循大驼峰命名。[不带参数]

#define kWidth self.frame.size.width

小驼峰命名。[带参数]

#define getImageUrl(url) [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",kBaseUrl,url]]

枚举类型命名:

Enum类型的命名与类的命名规则一致
Enum中枚举内容的命名需要以该Enum类型名称开头
NS_ENUM定义通用枚举,NS_OPTIONS定义位移枚举

typedef NS_ENUM(NSInteger,UIViewAnimationTransition) {
      UIViewAnimationTransitionNone,
      UIViewAnimationTransitionFlipFromLeft,
      UIViewAnimationTransitionFlipFromRight,          
      UIViewAnimationTransitionCurlUp,
      UIViewAnimationTransitionCurlDown
};

typedef NS_OPTIONS(NSUInteger,UIControlState) {
      UIControlStateNormal=0,
      UIControlStateHighlighted=1<<0,
      UIControlStateDisabled=1<<1

};

分组命名:

使用英文,首字母大写,之后每个单词首字母都大写
每个分组使用模块的名字
使用的开源库统一放在“Library”分组下
使用的公共组件统一放在“Common”分组下
视图控制器及AppDelegate统一放在“Controllers”分组下

后缀要求:

视图控制器的子类应该以“ViewController”或者“Controller”做后缀

CourseViewController

试图的子类应该以“View”做后缀

CourseView

协议(委托)使用Delegate或者DataSource作为后缀

VideoPlayerDelegate

按钮的子类应添加后缀“Button”,UI控件以此类推

LoginButton

2、注释

优秀的代码大部分是可以自描述的,我们完全可以用代码本身来表达它到底在干什么,而不需要注释的辅助,如果做不到命名尽量的见名知意的话,就可以适当的添加一些注释或者mark。

但是以下三种情况比较适合写注释:

1、公共接口(注释要告诉阅读代码的人,当前类能实现什么功能)。
2、涉及到比较深层专业知识的代码(注释要体现出实现原理和思想)。
3、容易产生歧义的代码(但是严格来说,容易让人产生歧义的代码是不允许存在的)。

除了上述这三种情况,如果别人只能依靠注释才能读懂你的代码的时候,就要反思代码出现了什么问题。对于注释的内容,相对于“做了什么”,更应该说明“为什么这么做”。

注释示例:

1、属性注释

/// 学生
@property (nonatomic, strong) Student *student;

2、类注释

/** 类信息。此注释用在类声明的开头。
@TestClass
@这是一个测试类
*/
@interfaceTestClass :UIView

@end

3、方法命名注释

/**
 根据请求的 URL 与 parameters 同步取出缓存数据
 @param  URL        请求的URL
 @param  parameters 请求的参数
 @return  缓存的服务器数据
*/
+ (id)httpCacheForURL:(NSString *)URL parameters:(id)parameters;

4、import注释
如果有一个以上的import语句,就对这些语句进行分组,每个分组的注释是可选的。

// Frameworks
#import<Foundation/Foundation.h>;

// Models
#import "UserInfoModel.h"

// Views
#import "CourseCountView"
#import "MineHeaderView.h"

5、代码块注释
单行的用//+空格开头,多行的采用/* */注释

//    [self.allCourseV dataWithTitle:@"购买课时" count:[NSString stringWithFormat:@"%lu", (unsigned long)allCount] desc:@""];

6、TODO
使用//TODO:说明 标记一些未完成的或完成的不尽如人意的地方

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

{
    //TODO:增加初始化
    return YES;
}

3、格式化代码

1、 指针 "*" 位置

定义一个对象时,指针 "*" 靠近变量

 NSString *userName;

2、 方法的声明和定义

在 - 、+ 和 返回值 之间留一个空格,方法名和第一个参数之间不留空格

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;

3、 代码缩进

  1. 使用 xcode 默认缩进,即 tab = 4空格
  2. 使用 xcode 中 re-indent 功能定期对代码格式进行整理,步聚:点选要进行重构的文档, Control+A 全选该文档,然后选择XCODE -> Editor -> Structure -> Re-Indent 即可对代码进行重构 !
  3. 相同类型变量声明需要独行声明

4、对方法进行分组

使用 #pragma mark -方式对类的方法进行分组
方法与方法之间空一行

#pragma mark - private methods
- (**void**)samplePrivateMethod
 {...}

- (**void**)sampleForIf
 {...}

5、 大括号写法

对于类的method: 左括号另起一行写(遵循苹果官方文档)
对于其他使用场景(if,for,while,switch等): 左括号跟在第一行后边

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

任何需要写大括号的部分,不得省略

//错误示例
- (void)wrongExamples
{
    BOOL someCondition = YES;
    if (someCondition)
        NSLog(@"this is wrong!!!");
    while (someCondition)
        NSLog(@"this is wrong!!!");
}

4、编码规范

1、if语句

①、须列出所有分支(穷举所有的情况),而且每个分支都须给出明确的结果。

推荐

var hintStr;
if (count <3) {
    hintStr ="Good";
} else {
    hintStr ="";
}

不推荐

var hintStr;
if (count <3) {
    hintStr ="Good";
}

②、不要使用过多的分支,要善于使用return来提前返回错误的情况,把最正确的情况放到最后返回。

推荐

if (!user.UserName) return NO;
if (!user.Password) return NO;
if (!user.Email) return NO;
return YES;

不推荐

BOOL isValid = NO;
if (user.UserName)
{
    if (user.Password)
    {
        if (user.Email) isValid = YES;
    }
}
return isValid;

③、条件过多,过长的时候应该换行(1)。条件表达式如果很长,则需要将他们提取出来赋给一个BOOL值(2),或者抽取出一个方法(3)
(1)

if(condition1 &&
    condition2 &&
    condition3 &&
    condition4) {
    // Do something
}

(2)

BOOL finalCondition = condition1 && condition2 && condition3 && condition4
if  (finalCondition) {
    // Do something
}

(3)

if ([self canDelete]){
    // Do something
}

- (BOOL)canDelete
{
    BOOL finalCondition1 = condition1 && condition2
    BOOL finalCondition2 =  condition3 && condition4
    return condition1 && condition2;
}

不推荐

if (condition1 && condition2 && condition3 && condition4) {
    // Do something
}

④、条件语句的判断应该是变量在右,常量在左。
if (object == nil)容易误写成赋值语句, if (!object)写法很简洁

推荐

if (6== count) {

}

if (nil == object) {

}

if (!object) {

}

不推荐

if(count == 6) {

}

if(object == nil) {

}

⑤、每个分支的实现代码都须被大括号包围
推荐:

if (!error) {
    return success;
}

也可以:

if (!error) return success;

不推荐

if (!error)
    return success;

2、for语句
①、不可在for循环内修改循环变量,防止for循环失去控制。
②、避免使用continue和break。

  • continue和break所描述的是“什么时候不做什么”,所以为了读懂二者所在的代码,我们需要在头脑里将他们取反。
  • 最好不要让这两个东西出现,因为我们的代码只要体现出“什么时候做什么”就好了,而且通过适当的方法,是可以将这两个东西消灭掉的:
  • 如果出现了continue,只需要把continue的条件取反即可
var filteredProducts = Array()
for level in products {
    if level.hasPrefix("bad") {
        continue;
    }
    filteredProducts.append(level)
}

我们可以看到,通过判断字符串里是否含有“bad”这个prefix来过滤掉一些值。其实我们是可以通过取反,来避免使用continue的:

for level in products {
    if !level.hasPrefix("bad") {
        filteredProducts.append(level)
    }
}

消除 while 里的 break:将 break 的条件取反,并合并到主循环里
在 while 里的 break 其实就相当于“不存在”,既然是不存在的东西就完全可以在最开始的条件语句中将其排除。
while 里的 break:

while (condition1) {
    ...
    if (condition2) {
        break;
    }
}

取反并合并到主条件:

while (condition1 && !condition2) {
    ...
}

在有返回值的方法里消除break:将break转换为return立即返回

//在有返回值的方法里break之后,再返回某个值。其实完全可以在break的那一行直接返回。
func hasBadProductIn(products: Array<String>) -> Bool {
    var result = false
    for level in products {
        if level.hasPrefix("bad") {
            result = true
            break
        }
    }
    return result
}
//这样写的话不用特意声明一个变量来特意保存需要返回的值,看起来非常简洁,可读性高。
func hasBadProductIn(products: Array<String>) -> Bool {
    for level in products {
        if level.hasPrefix("bad") {
           return true
        }
    }
    return false
}

3、Switch语句

①、每个分支都必须用大括号括起来

switch (integer) {
    case 1: {
        // ...
       break;
    } 
    case 2: {
        // ...
        break;
    }
    default: {
        // ...
        break;
    }
}

②、使用枚举类型时,不能有default分支, 除了使用枚举类型以外,都必须有default分支,在Switch语句使用枚举类型的时候,如果使用了default分支,在将来就无法通过编译器来检查新增的枚举类型了。

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

4、函数

①、一个函数只做一件事(单一原则)
②、对于有返回值的函数(方法),每一个分支都必须有返回值
③、对输入参数的正确性和有效性进行检查,参数错误立即返回
④、如果在不同的函数内部有相同的功能,应该把相同的功能抽取出来单独作为另一个函数
⑤、将函数内部比较复杂的逻辑提取出来作为单独的函数

5、团队规范

说明:一个好的团队,理所当然有其严格的代码规范,好的代码不仅可以提高团队的开放效率,也更利于团队项目的后期维护,统一的代码风格,也是团队的核心,所以规范代码很有必要!

1、删除多余的空行 所有方法与方法之间空1行 所有代码块之间空1行

2、删除多余的注释
删除注释掉的代码
删除没有意义的注释

3、删除多余的方法
如果方法没有使用到,请删除它
如果方法没有执行任何业务逻辑,请删除它或者给出一定注释

4、删除未被使用的资源文件

5、添加必要的注释
所有.h 文件中的property 需要给出注释
所有自定义的方法需要给出注释
比较大的代码块需要给出注释
所有代码中出现的阿拉伯数字需要给出注释
程序中出现加密/解密 逻辑的操作地方,需要给出注释说明过程(无论是系统还是自定义)

6、整体代码风格需要统一
代码后面的”{“ 不需要单独占用一行
逻辑运算符 与“|” 代码之前空一格
“#pragmamark -” 与下面的代码之前不要空行
遵循一般性的代码规范

参考:

iOS团队编程规范

【iOS】命名规范

iOS开发代码规范(通用)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 一、命名规范 1、统一要求含义清楚,尽量做到不需要注释也能了解其作用,若做不到,就加注释,使用全称,不使用缩写。 ...
    Untils阅读 544评论 0 0
  • iOS编程规范0规范 0.1前言 为􏰀高产品代码质量,指导广大软件开发人员编写出简洁、可维护、可靠、可 测试、高效...
    iOS行者阅读 4,431评论 21 35
  • -------------------------------------编码原则----------------...
    yanhooIT阅读 822评论 0 11
  • 这里有些关于编码风格Apple官方文档,如果有些东西没有提及,可以在以下文档来查找更多细节: The Object...
    Loki9527阅读 392评论 0 0
  • ——李茂英 窟野河畔寂樓臺 日落西山醉歸來 遠道冬風入我懷 老樹蕭蕭踏荒苔 附:欲脩其身者先正其心欲正其心...
    李茂英阅读 273评论 1 11