欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

IOS开发(36)之iOS 编码规范

程序员文章站 2023-11-09 23:53:46
一,格式化代码 ctrl + i ◦ 指针“*”号的位置 ▪ 如:nsstring*varname; ◦...

一,格式化代码 ctrl + i


◦ 指针“*”号的位置
▪ 如:nsstring*varname;


◦ 空格 vs tabs
▪ 只允许使用空格,将编辑器设置为1个tab = 4个字符缩进


◦ 每行的长度
▪ 每行最多不得超过100个字符
▪ 以15寸macbook pro的大小,每行100个字符时能最大化地同时容下编辑器和iphone模拟器
▪ google的80字符的标准有点少,这导致过于频繁的换行(objectve-c的代码一般都很长)
▪ 通过 “xcode => preferences => textediting => 勾选show page guide / 输入
100 => ok” 来设置提醒


{} 大括号均单独占一行,
◦ 方法的声明和定义
▪ 在 -  + 和返回值之间留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
{
...
}


◦ 方法的调用
▪ 调用方法沿用声明方法的习惯。例外:如果给定源文件已经遵从某种习惯,继续遵从那种习惯。
▪ 所有参数应在同一行中,或者每个参数占用一行且使用冒号对齐。如:
[myobject dofoowith:arg1 name:arg2 error:arg3];

[myobject dofoowith:arg1
name:arg2
error:arg3];
▪ 和方法的声明一样,如果无法使用冒号对齐时,每个参数一行、缩进4个字符、垂直对其(而非
使用冒号对齐)。如:
[myobj short:arg1
longkeyword:arg2
evenlongerkeyword:arg3];


◦ @public 和 @private
▪ @public 和 @private使用单独一行,不需要缩进


◦ protocals
▪ 类型标示符、代理名称、尖括号间不留空格。
▪ 该规则同样适用于:类声明、实例变量和方法声明。如:
@interface myprotocoledclass : nsobject<nswindowdelegate> {
@private
id<myfancydelegate> _delegate;
}
- (void)setdelegate:(id<myfancydelegate>)adelegate;
@end
▪ 如果类声明中包含多个protocal,每个protocal占用一行,缩进2个字符。如:
@interface customviewcontroller : viewcontroller<
abcdelegate,
defdelegate
> {
...
}


二,命名


◦ 类名
▪ 类名(及其category name 和 protocal name)的首字母大写,写使用首字母大写的形式分割单词
▪ 在面向特定应用的代码中,类名应尽量避免使用前缀,每个类都使用相同的前缀影响可读性。
▪ 在面向多应用的代码中,推荐使用前缀。如:gtmsendmessage


◦ category   name
▪ 待完善


◦ 方法名
▪ 方法名的首字母小写,且使用首字母大写的形式分割单词。方法的参数使用相同的规则。
▪ 方法名+参数应尽量读起来像一句话(如:)(错,尽量避免,不是写文章,坚持c++风格)。在这里查看苹果对方法命名的规范。
▪ 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。如:
@interface myclass : nsobject {
@private
id _myinstancevariable;
}
// public accessors, setter takes ownership
- (id)myinstancevariable;
- (void)setmyinstancevariable:(id)thevar;
@end


◦ indentify designated initializer
▪ 待完善


◦ override desingated initializer
▪ 待完善


◦ 初始化
▪ 在初始化方法中,不要将变量初始化为“0”或“nil”,那是多余的
▪ 内存中所有的新创建的对象(isa除外)都是0,所以不需要重复初始化为“0”或“nil”


◦ 避免显式的调用 +new 方法
▪ 禁止直接调用 nsobject 的类方法 +new,也不要在子类中重载它。使用alloc和init方法


◦ 保持公共api的简洁性
▪ 待完善


◦ #import vs #include
▪ 使用 #import 引入ojbective-c和ojbective-c++头文件,使用 #include 引入c和c++头文件


◦ import根框架(root frameworks),而非各单个文件
▪ 虽然有时我们仅需要框架(如cocoa 或 foundation)的某几个头文件,但引入根文件编译
器会运行的更快。因为根框架(root frameworks)一般会预编译,所以加载会更快。再次强
调:使用 #import 而非 #include 来引入objective-c框架。如:
#import <foundation/nsarray.h> // 禁止
#import <foundation/nsstring.h>
...
#import <foundation/foundation.h> // 对头


◦ 创建对象时尽量使用autorelease
▪ 创建临时对象时,尽量同时在同一行中 autorelease 掉,而非使用单独的 release 语句
▪ 虽然这样会稍微有点慢,但这样可以阻止因为提前 return 或其他意外情况导致的内存泄露。
通盘来看这是值得的。如:
// 避免这样使用(除非有性能的考虑)
mycontroller* controller = [[mycontroller alloc] init];
// ... 这里的代码可能会提前return ...
[controller release];


// 这样更好
mycontroller* controller = [[[mycontroller alloc] init] autorelease];


◦ 先autorelease,再retain
▪ 在为对象赋值时,遵从“先autorelease,再retain”
▪ 在将一个新创建的对象赋给变量时,要先将旧对象release掉,否则会内存泄露。市面上有很
多方法来handle这种情况,这里选择“先autorelease,再retain”的方法,这种方法不易引
入error。注意:在循环中这种方法会“填满”autorelease pool,稍稍影响效率,但是
google和我( :p )认为这个代价是可以接受的。如:
- (void)setfoo:(gmfoo *)afoo {
[foo_ autorelease]; // 如果foo_和afoo是同一个对象(foo_ == afoo),dealloc不会被调用
foo_ = [afoo retain];
}


◦ dealloc的顺序要与变量声明的顺序相同
▪ 这有利于review代码
▪ 如果dealloc中调用其他方法来release变量,将被release的变量以注释的形式标注清楚


◦ nsstring的属性的setter使用“copy”
▪ 禁止使用retain,以防止意外的修改了nsstring变量的值。如:
- (void)setfoo:(nsstring *)afoo {
[foo_ autorelease];
foo_ = [afoo copy];
}

@property (nonatomic, copy) nsstring *astring;


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


◦ 对 nil 的检查
▪ 仅在有业务逻辑需求时检查 nil,而非为了防止崩溃
▪ 向 nil 发送消息不会导致崩溃,objective-c运行时负责处理。


◦ bool陷阱
▪ 将int值转换为bool时应特别小心。避免直接和yes比较
▪ objective-c中,bool被定义为unsigned char,这意味着除了 yes (1) 和 no (0)外它
还可以是其他值。禁止将int直接转换(cast or convert)为bool。
▪ 常见的错误包括:将数组的大小、指针值或位运算符的结果转换(cast or convert)为
bool,因为该bool值的结果取决于整型值的最后一位
▪ 将整型值转换为bool的方法:使用三元运算符返回yes / no,或使用位运算符(&&, ||, !)
▪ bool、_bool和bool之间的转换是安全的,但是bool和boolean间的转换不是安全的,所以
将boolean看成整型值。
▪ 在objective-c中,只允许使用bool
▪ 如:
// 禁止
- (bool)isbold {
return [self fonttraits] & nsfontboldtrait;
}
- (bool)isvalid {
return [self stringvalue];
}
// 对头
- (bool)isbold {
return ([self fonttraits] & nsfontboldtrait) ? yes : no;
}
- (bool)isvalid {
return [self stringvalue] != nil;
}
- (bool)isenabled {
return [self isvalid] && [self isbold];
}
▪ 禁止直接将bool和yes/no比较,如:
// 禁止
bool great = [foo isgreat];
if (great == yes)
...
// 对头
bool great = [foo isgreat];
if (great)
...


◦ 属性
▪ 命名:与去掉“_”前缀的成员变量相同,使用@synthesize将二者联系起来。如:
// abcd.h
@interface myclass : nsobject {
@private
nsstring *_name;
}
@property (copy, nonatomic) nsstring *name;
@end


// abcd.m
@implementation myclass
@synthesize name = _name;
@end
▪ 位置:属性的声明紧随成员变量块之后,中间空一行,无缩进。如上例所示
▪ 严把权限:对不需要外部修改的属性使用readonly
▪ nsstring使用copy而非retain
▪ cftype使用@dynamic, 禁止使用@synthesize
▪ 除非必须,使用nonatomic


五, cocoa pattern


◦ delegate pattern(委托)
▪ delegate对象使用assign,禁止使用retain。因为retain会导致循环索引导致内存泄露,
并且此类型的内存泄露无法被instrument发现,极难调试
▪ 成员变量命名为_delegate,属性名为delegate


◦ model/view/controller
▪ model和view分离
▪ 不多解释
▪ controller独立于view和controller
▪ 不要在与view相关的类中添加过多的业务逻辑代码,这让代码的可重用性很差
▪ controller负责业务逻辑代码,且controller的代码与view尽量无关
▪ 使用 @protocal 定义回调apis,如果并非所有方法都是必须的,使用 @optional 标示


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