Objective-C编码风格指南

参考资料:

•Apple:CodingGuidelinesforCocoa

•Google:Objective-CStyleGuide

•Three20:Sourcecodestyleguildelines

正文:

•格式化代码

◦指针“*”号的位置

▪如:NSString*varName;

◦空格VStabs

▪只允许使用空格,将编辑器设置为1个TAB=2个字符缩进

◦每行的长度

▪每行最多不得超过100个字符

▪以15寸MacbookPro的大小,每行100个字符时能最大化地同时容下编辑器和iPhone模拟器

▪Google的80字符的标准有点少,这导致过于频繁的换行(Objectve-C的代码一般都很长)

▪通过“Xcode=>Preferences=>TextEditing=>勾选ShowPageGuide/输入

100=>OK”来设置提醒◦方法的声明和定义

▪在-OR+和返回值之间留1个空格,方法名和第一个参数间不留空格。如:-(void)doSomethingWithString:(NSString*)theString{

...}

▪当参数过长时,每个参数占用一行,以冒号对齐。如:-(void)doSomethingWith:(GTMFoo*)theFoo

rect:(NSRect)theRect

interval:(float)theInterval{

...}

▪如果方法名比参数名短,每个参数占用一行,至少缩进4个字符,且为垂直对齐(而非使用冒号对齐)。如:

-(void)short:(GTMFoo*)theFoo

longKeyword:(NSRect)theRect

evenLongerKeyword:(float)theInterval{

...

}

◦方法的调用

▪调用方法沿用声明方法的习惯。例外:如果给定源文件已经遵从某种习惯,继续遵从那种习惯。

▪所有参数应在同一行中,或者每个参数占用一行且使用冒号对齐。如:

[myObjectdoFooWith:arg1name:arg2error:arg3];

[myObjectdoFooWith:arg1

name:arg2

error:arg3];

▪和方法的声明一样,如果无法使用冒号对齐时,每个参数一行、缩进4个字符、垂直对其(而非使用冒号对齐)。如:

[myObjshort:arg1

longKeyword:arg2

evenLongerKeyword:arg3];

◦@public和@private

▪@public和@private使用单独一行,且缩进1个字符

◦Protocals

▪类型标示符、代理名称、尖括号间不留空格。

▪该规则同样适用于:类声明、实例变量和方法声明。如:

@interfaceMyProtocoledClass:NSObject<NSWindowDelegate>{

@private

id<MyFancyDelegate>_delegate;

}

-(void)setDelegate:(id<MyFancyDelegate>)aDelegate;

@end

▪如果类声明中包含多个protocal,每个protocal占用一行,缩进2个字符。如:@interfaceCustomViewController:ViewController<

AbcDelegate,

DefDelegate>{

...}

•命名

◦类名

▪类名(及其categoryname和protocalname)的首字母大写,写使用首字母大写的形式分割单词

▪在面向特定应用的代码中,类名应尽量避免使用前缀,每个类都使用相同的前缀影响可读性。

▪在面向多应用的代码中,推荐使用前缀。如:GTMSendMessage◦CategoryName

▪待完善◦方法名

▪方法名的首字母小写,且使用首字母大写的形式分割单词。方法的参数使用相同的规则。

▪方法名+参数应尽量读起来像一句话(如:)。在这里查看苹果对方法命名的规范。

▪getter的方法名和变量名应相同。不允许使用“get”前缀。如:

-(id)getDelegate;//禁止

-(id)delegate;//对头

▪本规则仅针对Objective-C代码,C++代码使用C++的习惯

◦变量名

▪变量名应使用容易意会的应用全称,且首字母小写,且使用首字母大写的形式分割单词

▪成员变量使用“_”作为前缀(如:“NSString*_varName;”。虽然这与苹果的标准(使

用“_”作为后缀)相冲突,但基于以下原因,仍使用“_”作为前缀。

▪使用“_”作为前缀,更容易在有代码自动补全功能的IDE中区分“属性

(self.userInfo)”和“成员变量(_userInfo)”

▪常量(#define,enums,const等)使用小写“k”作为前缀,首字母大写来分割单词。如:

kInvalidHandle

•注释

◦待完善

•Cocoa和Objective-C特有的规则

成员变量使用@private。如:

@interfaceMyClass:NSObject{

@private

id_myInstanceVariable;

}

//publicaccessors,settertakesownership

-(id)myInstanceVariable;

-(void)setMyInstanceVariable:(id)theVar;

@end

IndentifyDesignatedInitializer▪待完善

OverrideDesingatedInitializer

▪待完善◦初始化

▪在初始化方法中,不要将变量初始化为“0”或“nil”,那是多余的

▪内存中所有的新创建的对象(isa除外)都是0,所以不需要重复初始化为“0”或“nil”◦避免显式的调用+new方法

▪禁止直接调用NSObject的类方法+new,也不要在子类中重载它。使用alloc和init方法◦保持公共API的简洁性

▪待完善

◦#importVS#include

▪使用#import引入Ojbective-C和Ojbective-C++头文件,使用#include引入C和C++头文件

◦import根框架(rootframeworks),而非各单个文件

▪虽然有时我们仅需要框架(如Cocoa或Foundation)的某几个头文件,但引入根文件编译

器会运行的更快。因为根框架(rootframeworks)一般会预编译,所以加载会更快。再次强调:使用#import而非#include来引入Objective-C框架。如:

#import<Foundation/NSArray.h>//禁止

#import<Foundation/NSString.h>

...

#import<Foundation/Foundation.h>//对头◦创建对象时尽量使用autorelease

▪创建临时对象时,尽量同时在同一行中autorelease掉,而非使用单独的release语句

▪虽然这样会稍微有点慢,但这样可以阻止因为提前return或其他意外情况导致的内存泄露。

通盘来看这是值得的。如:

//避免这样使用(除非有性能的考虑)

MyController*controller=[[MyControlleralloc]init];

//...这里的代码可能会提前return...

[controllerrelease];

//这样更好

MyController*controller=[[[MyControlleralloc]init]autorelease];

◦先autorelease,再retain

▪在为对象赋值时,遵从“先autorelease,再retain”

▪在将一个新创建的对象赋给变量时,要先将旧对象release掉,否则会内存泄露。市面上有很

多方法来handle这种情况,这里选择“先autorelease,再retain”的方法,这种方法不易引入error。注意:在循环中这种方法会“填满”autoreleasepool,稍稍影响效率,但是Google和我()认为这个代价是可以接受的。如:

-(void)setFoo:(GMFoo*)aFoo{

[foo_autorelease];//如果foo_和aFoo是同一个对象(foo_==aFoo),dealloc不会被调用

foo_=[aFooretain];

}

◦dealloc的顺序要与变量声明的顺序相同

▪这有利于review代码

▪如果dealloc中调用其他方法来release变量,将被release的变量以注释的形式标注清楚

◦NSString的属性的setter使用“copy”

▪禁止使用retain,以防止意外的修改了NSString变量的值。如:

-(void)setFoo:(NSString*)aFoo{

[foo_autorelease];

foo_=[aFoocopy];

}

@property(nonatomic,copy)NSString*aString;

◦避免抛出异常(ThrowingExceptions)▪待完善

◦对nil的检查

▪仅在有业务逻辑需求时检查nil,而非为了防止崩溃

▪向nil发送消息不会导致系统崩溃,Objective-C运行时负责处理。◦BOOL陷阱

▪将int值转换为BOOL时应特别小心。避免直接和YES比较

▪Objective-C中,BOOL被定义为unsignedchar,这意味着除了YES(1)和NO(0)外它

还可以是其他值。禁止将int直接转换(castorconvert)为BOOL。

▪常见的错误包括:将数组的大小、指针值或位运算符的结果转换(castorconvert)为

BOOL,因为该BOOL值的结果取决于整型值的最后一位

▪将整型值转换为BOOL的方法:使用三元运算符返回YES/NO,或使用位运算符(&&,||,!)

▪BOOL、_Bool和bool之间的转换是安全的,但是BOOL和Boolean间的转换不是安全的,所以

将Boolean看成整型值。

▪在Objective-C中,只允许使用BOOL

▪如:

//禁止

-(BOOL)isBold{

return[selffontTraits]&NSFontBoldTrait;

}

-(BOOL)isValid{

return[selfstringValue];

}

//对头

-(BOOL)isBold{

return([selffontTraits]&NSFontBoldTrait)?YES:NO;

}

-(BOOL)isValid{

return[selfstringValue]!=nil;

}

-(BOOL)isEnabled{

return[selfisValid]&&[selfisBold];

}

▪禁止直接将BOOL和YES/NO比较,如://禁止

BOOLgreat=[fooisGreat];

if(great==YES)

...

//对头

BOOLgreat=[fooisGreat];if(great)

...

◦属性

▪命名:与去掉“_”前缀的成员变量相同,使用@synthesize将二者联系起来。如:

//abcd.h

@interfaceMyClass:NSObject{

@private

NSString*_name;

}

@property(copy,nonatomic)NSString*name;

@end

//abcd.m

@implementationMyClass

@synthesizename=_name;

@end

▪位置:属性的声明紧随成员变量块之后,中间空一行,无缩进。如上例所示▪严把权限:对不需要外部修改的属性使用readonly

▪NSString使用copy而非retain

▪CFType使用@dynamic,禁止使用@synthesize

▪除非必须,使用nonatomic•CocoaPattern

◦DelegatePattern(委托)

▪delegate对象使用assign,禁止使用retain。因为retain会导致循环索引导致内存泄露,

并且此类型的内存泄露无法被Instrument发现,极难调试

▪成员变量命名为_delegate,属性名为delegate

◦Model/View/Controller▪Model和View分离

▪不多解释

▪Controller独立于View和Controller

▪不要在与view相关的类中添加过多的业务逻辑代码,这让代码的可重用性很差

▪Controller负责业务逻辑代码,且Controller的代码与view尽量无关

▪使用@protocal定义回调APIs,如果并非所有方法都是必须的,使用@optional标示

•其他

◦init方法和dealloc方法是是最常用的方法,所以将他们放在类实现的开始位置◦使用空格将相同的变量、属性对齐,使用换行分组

相关推荐