Object-C编码规范
格式
1、任意函数长度不得超过50行。
2、任意行代码不得超过80字符。可以在设置中设置超过80个字符的提醒。
3、在定义函数的行前留白一行。
4、功能相近的代码要放在一起。
5、使用#pragma来切分不同功能区域的代码。
6、二元运算符和参数之间需要放置一个空格,一元运算符、强制类型转换和参数之间不放置空格。关键字之后圆括号之前需要放置一个空格。
1 | void *ptr = &value + 10 * 3; |
7、长的字面值应被拆分为多行。
1 | NSArray *theShit = @[ |
命名
命名是编程中最基本的技能,我们给变量、函数、类、包等等命名。给他们以名字,让他们有意义,既能表示他们到底是做什么的,也能将其与其他变量区别开来。像人一样娶一个好名字至关重要,“丁当”总比“狗蛋”来的好听。 为什么要命名? 命名一定要“名副其实”,尽可能使用有意的名称,而且这个意义和指称的变量真实意义相关。
1、基本原则
尽量不要出现没有任何意义的命名类似于下述形式的命名:
1 | int a = 1; |
如果换成下面的形式是不是可读性强了很多:
1 | int startX = 1; |
命名首字母大写,其他命名首字母小写。并且采用驼峰格式分割单词。 例如:FXTest
仿照 Cocoa 风格来,使用长命名风格。
变量命名推荐的命名语素顺序是:最开头是命名空间简写,然后越重要、区别度越大的语素越要往前放。经典的结构是:作用范围+限定修饰+类型。
1 | extern ushort APIDefaultPageSize; // 还行,能明白意思了 |
2、类别的扩展名以“被扩展的类名+自定义命名部分组成” 例如:
1 | NSSstring+Utils.h |
3、通知命名
基本命名格式是:与通知相关的类名
+ Did | Will
+ UniquePartOfName
+ Notification
,例:
1 | NSApplicationDidBecomeActiveNotification |
4、宏定义,全部字母大写,例如: #define BW_DEBUG 1
5、常量定义,字符串定义以小写字母k开头,随后首字母大写,例如:
1 | static NSString* const kBWBarTitle = @"动态"; |
ps:如果要定义常量使用static const优于宏定义,前者会进行类型检查。
6、缩略词,以下是一些常用的首字母缩略词:
1 | ASCII,PDF,XML,HTML,URL,RTF,HTTP,TIFF,JPG,PNG,GIF,LZW,ROM,RGB,CMYK,MIDI,FTP |
7、命名空间,因为OC没有命名空间的概念,所以使用前两个或者多个字母来表示命名空间,例如"NSObject中的NS"
,我们也使用自己的命名空间。比如:
1 | 发现模块:DiscoverController,模块里面其他的控件或者model,DCModel,DCView |
点标记语法
推荐:
1 | view.backgroundColor = [UIColor orangeColor]; |
不推荐:
1 | [view setBackgroundColor:[UIColor orangeColor]]; |
方法命名
1、方法命名尽可能清晰
推荐:
1 | insertObject:atIndex: |
不推荐:
1 | insert:at: |
2、类方法声明在方法类型与返回类型之间要有空格。
推荐:
1 | - (void)methodName:(NSString *)string; |
不推荐:
1 | -(void)methodName:(NSString *)string; |
3、函数
(1)、调用时所有参数应该在同一行
1 | [myObject doFooWith:arg1 name:arg2 error:arg3]; |
(2)、或者每行一个参数,以冒号对齐:
1 | [myObject doFooWith:arg1 |
对于参数过多的函数,尽量使用后面一种对其方式。
(3)、不要使用下面的缩进风格:
1 | [myObject doFooWith:arg1 name:arg2 // some lines with >1 arg |
(4)、如果对传入参数进行数据保护尽量不要用if(!objc)
,使用断言来处理。
1 | - (void)sendArgs:(NSDictionary*)args { |
(5)、方法参数名前一般使用的前缀包括“the”、“an”、“new”。示例:
1 | - (void)setTitle:(NSString *)aTitle; |
4、方法名
以 alloc
、copy
、init
、mutableCopy
、new
开头的方法要注意,它们会改变ARC的行为。
以 get
、set
开头的方法有特殊的意义,不要随意定义。
set
是属性默认的设置方法,如果函数不是为了设置类成员,则不要用set
开头,可用setup
替代。get
和属性方法无关,但在 Cocoa 中,其标准行为是通过引用传值,而不是直接返回结果的。欲获取变量,直接以变量名为名,如:userInfomation
,而不是getUserInfomation
。
例:
推荐:不推荐:1
2
3
4
5- (NSString *)name;
- (void)getName:(NSString **)buffer range:(NSRange)inRange;
- (NSSize)cellSize;
- (void)setupControllerObservers;
- (void)setupController;1
2
3- (NSString *)getName;
- (NSSize)calcCellSize;
- (void)setController;三元运算符
长的三元运算符应使用圆括号括起来。三元运算符仅用于赋值和做参数。当有nil时的三元运算符1
NSString *gender = (stuff == thing ? @"男" : @"女");
不推荐1
NSString *name = thingThatCouldBeNil ? defaultValue : @"";
1
NSString *name = thingThatCouldBeNil ?: defaultValue;
枚举类型
当使用enum
关键字时,推荐使用苹果最新引入的固定基础类型语法,因为这将获得强类型检查与代码完成功能。SDK现在包含了一个固定基础类型的宏—NS_ENUM()
。1
2
3
4
5
6
7typedef NS_ENUM(NSInteger, CertifiedModifyPassWordType)
{
CertifiedModifyPassWordTypeWithdrawals = 1, // 提现
CertifiedModifyPassWordTypePaymentFail, // 支付失败
CertifiedModifyPassWordTypePayment, // 支付
CertifiedModifyPassWordTypeOther
};布尔类型
因为nil被解析为了NO,所以和nil作比较没有任何的必要。不要将变量和YES直接比较,因为YES被定义为1而BOOL类型是8位的unsigned int,即BOOL的值不仅仅是1或0。
推荐:不推荐:1
2if (!someObject) {
}推荐:1
2if (someObject == nil) {
}不推荐:1
2if (isAwesome)
if (![someObject boolValue])1
2if ([someObject boolValue] == NO)
if (isAwesome == YES) // Never do this.单例
应该使用线程安全的模式创建共享的单例实例。单例的另一种做法,利用+ initialize方法。1
2
3
4
5
6
7
8+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}1
2
3
4
5
6
7static JSONAPI* sharedInstance = nil;
+ (void)initialize {
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedInstance = [[JSONAPI alloc] init];
});
}Block相关
在block中使用到self变量的时候,一定要先weak再strong。1
2
3
4
5
6
7__weak typeof(self) weakSelf = self;
[self doABlockOperation:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
...
}
}];Delegate
代理协议名,常用delegate、dateSource做结尾。以1
2- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;did
、will
、should
等形容词,代表Event事件的Delegate1
2
3- (BOOL)windowShouldClose:(id)sender;
- (void)browserDidScroll:(NSBrowser *)sender;
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window;控制结构,if-else
1、方法的花括号推荐另起一行。方法内部需要写在一行。2、条件判断的括号内侧不应有空格。1
2
3
4
5- (void)methodName:(NSString *)string {
if () {
} else {
}
}
推荐:不推荐:1
2
3if (a < b) {
// something
}3、关系运算符(如1
2
3if ( a < b ) {
// something
}>=
、!=
)和逻辑运算符(如&&
、||
)两边要有空格。二元算数运算符两侧是否加空格不确定,根据情况自己定。一元运算符与操作数之前没有空格。1
(someValue > 100) ? YES : NO
多个参数逗号后留一个空格(这也符合正常的西文语法)。
4、当需要满足一定条件时才执行某项操作时,使用return是正常合理的。
推荐:不推荐:1
2
3
4
5
6
7
8
9
10- (void)someMethod {
if (![someOther boolValue]) {
return;
}
//Do something important
}
if (!error) {
return success;
}1
2
3
4
5
6
7
8
9
10- (void)someMethod {
if ([someOther boolValue]) {
//Do something important
}
}
if (!error)
return success;
...
if (!error) return success;UIKit
UIView的子类初始化的时候,不要进行任何布局操作。布局操作在LayoutSubViews里面做。
UIView的子类布局必须在layoutSubViews里面进行,需要布局的时候调用setNeedLayout来告诉系统,需要重新布局该View,不要直接调用layoutSubViews。@class
在类定义中使用到自己定义的类的时候,尽量不要在头文件中引入自己定义的类的同文件,使用@class替换。在实现文件中引入相应头文件。例如:1
2
3
4
5
6
7
8
9
10// BWTest.h
@class BWDataCenter;
@interface BWTest : NSObject
@property (nonatomic, strong) BWDataCenter* dataCenter;
@end
// BWTest.m
#import "BWDataCenter.h"
@implementation BWTest
@end项目工程文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#pragma mark - init Method
填入init,initWithFrame等方法
#pragma mark- View Life Cycle
填入viewdidload,viewdidappear等方法
#pragma mark- Delegate,DataSource, Callback Method
填入tableview,scrollview等代理方法
#pragma mark- Override Parent Methods
填入updateViewConstraints,updateConstraint, prepareForSegue等方法
#pragma mark- SubViews Configuration
填入configureSubViews,configureTableView等方法,这里的方法在init方法或view life cycle被调用
#pragma mark- Actions
填入-(IBAction)action:(id)sender和[self addtarget:self action:@selector(action:)]动作指向的方法
#pragma mark- Public Methods
填入在.h外暴露的方法
#pragma mark- Private Methods
填入.m文件内部调用的方法
#pragma mark- Getter Setter
填入对@property初始化的方法