iOS 代码规范
2015-11-28 12:40 jiangys 阅读(792) 评论(0) 编辑 收藏 举报概述
命名的好坏在开发中往往也不怎么重视,毕竟差的命名也不会影响程序逻辑。但是不好的命名在大项目中带来的隐形维护成本是相当高的,这些在项目开始时可能还很难察觉,而后来会陷入前仆后继的维护困境中。我们往往非常重视项目逻辑的复杂性,却不能好好的把“简单”的命名做好。其实,如果简单的东西都做不好,那么做出再复杂的东西那也是垃圾。
命名规范
分类(类别)命名
与类命名相同,此外需添加要扩展的类名和“+”
举例:NSString+URLEncoding
协议(委托)命名
与类命名相同,此外需添加“Delegate”后缀
举例:ReplyViewDelegate
方法命名
首字母小写,之后每个单词首字母都大写
方法名使用动词短语
举例:- (void)setupPostWithValue:(int)value
“要什么”往往被胡乱命名为get
开头的方法。首先get是一个动词,所以它还是“做什么”或者说“做的是要什么”。那么get方法不要用于返回对象,但它可用于参数。
- (XXItem *)getItemAtIndex:(NSUInteger)index //Bad!! 不规范的命名 - (XXItem *)itemAtIndex:(NSUInteger)index //Good, 命名清晰 - (void)getItem:(XXItem **)outItem atIndex:(NSUInteger)index //比较符合规范,但第二种更好。
参数命名
首字母小写,之后每个单词首字母都大写
每个参数前要加参数的名称提示
举例:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil - (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender
对象命名
采用修饰+类型的方式
举例:
titleLabel //表示标题的label, 是UILabel类型 confirmButton //表示确认的button, 是UIButton类型
图片命名
使用英文,全部小写 ,添加模块名作为前缀,避免冲突 。图片应该与类文件一样,按模块分组放置
举例:
Home(界面名称)_(功能属性简写+描述).png
如: home_btn_recommended.png
或:
compose_mentionbutton_background@2x.png
compose_mentionbutton_background_highlighted@2x.png
分组命名
使用英文,首字母大写,之后每个单词首字母都大写
每个分组使用模块的名字
使用的开源库统一放在“Library”分组下
使用的公共组件统一放在“Common”分组下
使用资源统一放在"Resource"分组下,包括文件、音频、图片、证书等
编码规范
编码规范简单来说就是为了保证写出来的代码具备三个原则:可复用, 易维护, 可扩展. 这其实也是面向对象的基本原则. 可复用, 简单来说就是不要写重复的代码, 有重复的部分要尽量封装起来重用。
判断nil或者YES/NO
推荐:
if (someObject) { ... } if (!someObject) { ... }
不推荐:
if (someObject == YES) { ...} if (someObject != nil) { ...}
if (someObject == YES)容易误写成赋值语句
条件赋值
推荐:
result = object ? : [self createObject];
不推荐:
result = object ? object : [self createObject];
如果是存在就赋值本身, 简洁。
BOOL赋值
推荐:
BOOL isAdult = age > 18;
不推荐:
BOOL isAdult; if (age > 18) { isAdult = YES; } else { isAdult = NO; }
拒绝死值
推荐:
if (car == Car.Nissan) or const int adultAge = 18; if (age > adultAge) { ... }
不推荐:
if (carName == "Nissan") or if (age > 18) { ... }
死值每次修改的时候容易被遗忘, 地方多了找起来就悲剧了. 而且定义成枚举或者static可以让错误发生在编译阶段. 另外仅仅看到一个数字, 完全不知道这个数字代表的意义. 纳尼?
复杂的条件判断
推荐:
if ([self canDeleteJob:job]) { ... } - (BOOL)canDeleteJob:(Job *)job { BOOL invalidJobState = job.JobState == JobState.New || job.JobState == JobState.Submitted || job.JobState == JobState.Expired; BOOL invalidJob = job.JobTitle && job.JobTitle.length; return invalidJobState || invalidJob; }
不推荐:
if (job.JobState == JobState.New || job.JobState == JobState.Submitted || job.JobState == JobState.Expired || (job.JobTitle && job.JobTitle.length)) { //.... }
清晰明了, 每个函数DO ONE THING!
嵌套判断
推荐:
- (void) someMethod { if (![someOther boolValue]) { return; } //Do something important }
不推荐:
- (void) someMethod { if ([someOther boolValue]) { //Do something important } }
一旦发现某个条件不符合, 立即返回, 条理更清晰。
所有的逻辑块必须使用花括号包围,即使条件体只需编写一行代码也必须使用花括号
推荐:
if (!error) { return success; }
不推荐:
if (!error) return success; ... if (!error) return success;
参数过多
推荐:
- (void)registerUser(User *user) { // to do... }
不推荐:
- (void)registerUserName:(NSString *)userName password:(NSString *)password email:(NSString *)email { // to do... }
当发现实现某一功能需要传递的参数太多时, 就预示着你应该聚合成一个model类了...这样代码更整洁, 也不容易因为参数太多导致出错。
点标记语法
属性和幂等方法(多次调用和一次调用返回的结果相同)使用点标记语法访问,其他的情况使用方括号标记语法。
推荐:
view.backgroundColor = [UIColor orangeColor]; [UIApplication sharedApplication].delegate;
不推荐:
[view setBackgroundColor:[UIColor orangeColor]]; UIApplication.sharedApplication.delegate;
枚举
枚举使用Objective-C方式来定义,枚举命名是 类前缀+枚举名,枚举值要加枚举名。
举例:
typedef NS_ENUM(NSUInteger, HGMachineState) {
HGMachineStateNone,
HGMachineStateIdle,
HGMachineStateRunning,
HGMachineStatePaused
};
常量
常量应该类名称+“骆峰式”单词大写。
推荐:
static const NSTimeInterval HGSignInViewControllerFadeOutAnimationDuration = 0.4;
不推荐:
static const NSTimeInterval fadeOutTime = 0.4;
常数是优于串联字符串或数字的,允许多个地方使用常用变量,可以迅速改变不需要查找和替换。常量应该声明为静态常量而不使用宏定义,除非明确需要定义一个宏。
推荐:
static NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification"; static const CGFloat ZOCImageThumbnailHeight = 50.0f;
不推荐:
#define CompanyName @"Apple Inc." #define magicNumber 42
单例模式
使用GCD代替使用sharedInstance,每次调用+ (id)sharedInstance函数都会付出取锁的代价。
推荐:
+ (instancetype)sharedInstance { static id sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance; }
不推荐:
+ (instancetype)sharedInstance { static id sharedInstance; @synchronized(self) { if (sharedInstance == nil) { sharedInstance = [[MyClass alloc] init]; } } return sharedInstance; }
代理
定义一个协议是 类名+Delegate,并要使用weak 弱指针,协议使用可选@optional
@class ZOCSignUpViewController; @protocol ZOCSignUpViewControllerDelegate <NSObject> @required - (void)signUpViewController:(ZOCSignUpViewController *)controller didProvideSignUpInfo:(NSDictionary *); @optional - (void)signUpViewControllerDidPressSignUpButton:(ZOCSignUpViewController *)controller; @end @interface ZOCSignUpViewController : UIViewController @property (nonatomic, weak) id<ZOCSignUpViewControllerDelegate> delegate; @end
在发送委托代理方法之前,一定要先检查该委托方法已经被实现(否则会崩溃)。
if ([self.delegate respondsToSelector:@selector(signUpViewControllerDidPressSignUpButton:)]) { [self.delegate signUpViewControllerDidPressSignUpButton:self]; }
动画
推荐
[UIView animateWithDuration:1.0 animations:^{ // something } completion:^(BOOL finished) { // something }];
不推荐
[UIView animateWithDuration:1.0 animations:^{ // something } completion:^(BOOL finished) { // something }];
Pragma Mark
使用“#pargma mark - ”实现方法的分组。建议按下面几点单独分组:
1.功能分组
2.代理协议实现分组
3.重写父类方法
- (void)dealloc { /* ... */ } - (instancetype)init { /* ... */ } #pragma mark - View Lifecycle - (void)viewDidLoad { /* ... */ } - (void)viewWillAppear:(BOOL)animated { /* ... */ } - (void)didReceiveMemoryWarning { /* ... */ } #pragma mark - Custom Accessors - (void)setCustomProperty:(id)value { /* ... */ } - (id)customProperty { /* ... */ } #pragma mark - IBActions - (IBAction)submitData:(id)sender { /* ... */ } #pragma mark - Public - (void)publicMethod { /* ... */ } #pragma mark - Private - (void)zoc_privateMethod { /* ... */ } #pragma mark - UITableViewDataSource - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { /* ... */ } #pragma mark - ZOCSuperclass // ... overridden methods from ZOCSuperclass #pragma mark - NSObject - (NSString *)description { /* ... */ }
抽象方法定义
@interface TestClass : NSObject #pragma mark - Abstract Method //抽象方法 -(void)doWork; @end
抽象类不允许被实例化,所以需要在init方法中添加判断代码
@implementation TestClass - (id)init { if( [self class] == [TestClass class]) { @throw [NSException exceptionWithName:@"抽象类无法实例化" reason:@"抽象类无法实例化: TestClass" userInfo:nil]; } else { self = [super init]; if(self){ } return self; } } #pragma mark - Abstract Method - (void)doWork { @throw [NSException exceptionWithName:@"抽象方法没有被实现" reason:@"抽象方法没有被实现: doWork" userInfo:nil]; } @end
参数链接:
https://github.com/objc-zen/objc-zen-book
http://www.cocoachina.com/ios/20151014/13678.html
http://www.cocoachina.com/ios/20151118/14242.html