Table of Contents
iOS 编码规范
1 文件规范
1.1 文件编码
- 项目中文件均采用UTF-8编码格式
- 换行符使用Linux/Unix风格 LF(\n)
1.2 文件命名
- 类
类名.h (.m/.c/.cpp/.mm) - 分类
类名+分类名.h (.m)
2 编码格式
2.1 缩进
- 不使用Tab缩进
- 一次缩进两个空格
- 尽量控制行宽在80列内
2.2 方法 声明与调用
- 方法说明符与返回值间必须有一个空格
-
引用类型须在*号和类型间有一个空格
- (void)doSomethingWithString:(NSString *)theString { ... }
-
超过80列的方法名, 须换行将每个参数单独成一行
- (void)doSomethingWith:(GTMFoo *)theFoo rect:(NSRect)theRect interval:(float)theInterval { ... }
-
方法调用与声明基本一致, 根据是否大于80列决定是否将参数拆成单独行
2.3 异常
-
尽量不使用异常
-
如必须临时使用异常, 参考如下格式
@try { foo(); } @catch (NSException *ex) { bar(ex); } @finally { baz(); }
2.4 协议名
-
类型标识符和尖括号内的协议名之间,不能有任何空格。
@interface MyProtocoledClass : NSObject<NSWindowDelegate> - (void)setDelegate:(id<MyFancyDelegate>)aDelegate; @end
2.5 block(闭包)
取决于块的长度,下列都是合理的风格准则:
- 如果一行可以写完块,则没必要换行。
- 如果不得不换行,关括号应与块声明的第一个字符对齐。
- 块内的代码须按 4 空格缩进。
- 如果块太长,比如超过 20 行,建议把它定义成一个局部变量,然后再使用该变量。
- 如果块不带参数,^{ 之间无须空格。如果带有参数,( 之间无须空格,但 ) { 之间须有一个空格。
- 块内允许按两个空格缩进,但前提是和项目的其它代码保持一致的缩进风格。
示例如下:
// The entire block fits on one line.
[operation setCompletionBlock:^{ [self onOperationDone]; }];
// The block can be put on a new line, indented four spaces, with the
// closing brace aligned with the first character of the line on which
// block was declared.
[operation setCompletionBlock:^{
[self.delegate newDataAvailable];
}];
// Using a block with a C API follows the same alignment and spacing
// rules as with Objective-C.
dispatch_async(fileIOQueue_, ^{
NSString* path = [self sessionFilePath];
if (path) {
// ...
}
});
// An example where the parameter wraps and the block declaration fits
// on the same line. Note the spacing of |^(SessionWindow *window) {|
// compared to |^{| above.
[[SessionService sharedService]
loadWindowWithCompletionBlock:^(SessionWindow *window) {
if (window) {
[self windowDidLoad:window];
} else {
[self errorLoadingWindow];
}
}];
// An example where the parameter wraps and the block declaration does
// not fit on the same line as the name.
[[SessionService sharedService]
loadWindowWithCompletionBlock:
^(SessionWindow *window) {
if (window) {
[self windowDidLoad:window];
} else {
[self errorLoadingWindow];
}
}];
// Large blocks can be declared out-of-line.
void (^largeBlock)(void) = ^{
// ...
};
[operationQueue_ addOperationWithBlock:largeBlock];
2.6 编码风格
由于 Objective-C 与 C++ 可以完全混编, 这里根据如下规则进行解决:
编码风格取决于方法/函数以哪种语言实现。如果在一个 @implementation 语句中,就使用 Objective-C 的风格。如果实现一个 C++ 的类,就使用 C++ 的风格。这样避免了一个函数里面实例变量和局部变量命名规则混乱,严重影响可读性。
-
2.6.1 常量命名:
-
仅限于编译单元内, 前加 k (声明在.m)
-
在类外可见的, 以类名为前缀 (声明在.h)
外界可见常量名及其值
外界只见常量名不见其值 (隐藏细节) -
常量尽量避免使用宏定义, 优先使用 static const
#define ANIMATION_DURATION 0.3 //尽量避免这么做 // 推荐方式: // static : 仅在编译单元内可见 const : 不允许修改 static const NSTimeInterval kAnimationDuration = 0.3; // 1 static const NSTimeInterval EOCViewClassAnimationDuration = 0.3; // 2.1 // 2.2 这个常量会被加入全局符号表 // in .h extern NSString *const EOCStringConstant; // in .m NSString *consEOCStringConstant = @"VALUE";
-
-
2.6.2 普通变量名
尽量为变量起一个描述性的名字。不要担心浪费列宽,因为让新的代码阅读者立即理解你的代码更重要。
-
错误示例:
int w; int nerr; int nCompConns; tix = [[NSMutableArray alloc] init]; obj = [someObject object]; p = [network port];
-
正确示例:
int numErrors; int numCompletedConnections; tickets = [[NSMutableArray alloc] init]; userInfo = [someObject object]; port = [network port];
-
-
2.6.2 函数 & 方法
-
纯C函数 和 全局变量 (顶级符号) 必须加前缀(三字符以上的个人前缀)
-
分类方法名必须添加小写前缀(个人或公司缩写)
-
私有方法加前缀 p_
示例如下:/// 纯C函数 SQLITE_API int sqlite3_config(int, ...); /// 分类方法前缀 + (UIViewController*)sw_currentViewController:(UIView *)view; /// 私有方法 - (void)p_synchronizeDataArr;
-
必要时明确指定构造方法, 方便他人调用(如:不希望别人使用父类初始化方法构造时)
/// 唯一初始化方法 - (instancetype)initWithSecret:(BOOL)isSecret NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE;
-
不允许使用 +new 方法 创建对象!
-
NSString类型属性必须用copy修饰
- (void)setFoo:(NSString *)aFoo { foo_ = [aFoo copy]; // 防止调用者修改字符串 }
-
-
2.6.3 BOOL 相关陷阱
-
不要将普通整形转换成BOOL
-
不要将 BOOL值 与 YES或者NO 进行比较
BOOL great = [foo isGreat]; // 错误示例 if (great == YES) // ...be great! BOOL great = [foo isGreat]; // 正确示例 if (great) // ...be great!
-
-
2.6.4 循环引用
-
委托模式下委托对象不应被retain(strong修饰)
-
Weak-Strong-Dance并不能保证 block所引用对象的释放时机在执行之后, 更安全的做法应该是在 block 内部使用 strongSelf 时进行 nil检测,这样可以避免上述情况。
NTWeakself; [tmpCell setClickToEditBlock:^(NSString *text){ NTStrongself; if(!strongself) return; [strongself p_setUpEditOrInputView:text]; }];
-
网友评论