介绍
为什么会有这篇文档?
Objective-C编码规范的整理,整理的还不是很完整,还有待完善。
目录
代码组织
在.m文件中使用#pragma mark - 来分类方法,要遵循以下一般结构
#pragma mark - Lifecycle
- (instancetype)init {}
- (void)dealloc {}
- (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)privateMethod {}
#pragma mark - Protocol conformance
#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {}
#pragma mark - NSObject
- (NSString *)description {}
命名
命名必须使用驼峰命名法。
不要担心方法名或变量名过长,推荐使用描述性的方法或命名。
类名第一个字母必须大写
推荐:
UIButton *settingsButton;
UILabel *sharedProductCountLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 40)
不推荐:
UIButton *setBut;
NSNotification *noti;
UILabel *lab;
- (void)setBg:(UIColor *)color;
- (void)destSel:(NSString *)str;
常量应该使用驼峰式命名规则,所有的单词首字母大写和加上与类名有关的前缀,属性则不一样。
推荐:
static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3;
不推荐:
static NSTimeInterval const fadetime = 1.7;
属性的首单词的首字母应该小写。属性尽量使用auto-synthesis,最好不要手动编写@synthesize语句。
推荐:
@property (strong, nonatomic) NSString *descriptiveVariableName;
不推荐:
id varnm;
注释
当需要注释时,注释应该用来解释这段特殊代码为什么要这样做。任何被使用的注释都必须保持最新或被删除。
属性注释必须使用三个斜杠,这样子变量就会有代码提示。
/// 商品Id
@property (assign, nonatomic) NSInteger productId;
/// 下载地址
@property (copy, nonatomic) NSString *downloadUrl;
在Xcode 8中,方法使用系统的快捷键 Option(Alt) + Command + /,会自动类似以下的格式。
/**
Description
@param text text description
@param image image description
*/
- (void)setExampleText:(NSString *)text image:(UIImage *)image;
空格
- 方法的大括号和其他的大括号(
if
/else
/switch
/while
等等)总是在同一行语句打开,但在新行中关闭。
推荐:
if (user.isHappy) {
//Do something
} else {
//Do something else
}
不推荐:
if (user.isHappy)
{
//Do something
}
else {
//Do something else
}
- 方法之间应该正好空一行,这有助于视觉清晰度和代码组织性。在方法中的在方法内的空白应该分离功能,但通常都抽离出来成为一个新方法。
优先使用auto-synthesis。但如果有必要,
@synthesize
和@dynamic
应该在实现中每个都声明新的一行。应该避免以冒号对齐的方式来调用方法。因为有时方法签名可能有3个以上的冒号和冒号对齐会使代码更加易读。请不要这样做,尽管冒号对齐的方法包含代码块,因为Xcode的对齐方式令它难以辨认。
推荐:
NSInteger index = 1;
switch (index) {
case 1:
// Do something
break;
case 2:
// Do something
break;
case 3: {
// something
break;
}
default:
break;
}
// blocks are easily readable
[UIView animateWithDuration:1.0 animations:^{
// something
} completion:^(BOOL finished) {
// something
}];
不推荐:
// colon-aligning makes the block indentation hard to read
[UIView animateWithDuration:1.0
animations:^{
// something
}
completion:^(BOOL finished) {
// something
}];
方法
在写方法的时候,注意在方法类型(-/+ 符号)之后有一个空格。在方法各个段之间应该也有一个空格(符合Apple的风格)。
在参数之前应该包含一个具有描述性的关键字来描述参数。
推荐:
- (void)setExampleText:(NSString *)text image:(UIImage *)image;
- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
- (id)viewWithTag:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
不推荐:
-(void)setT:(NSString *)text i:(UIImage *)image;
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
- (id)taggedView:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
- (instancetype)initWith:(int)width and:(int)height; // Never do this.
变量
变量尽量以描述性的方式来命名。
星号表示变量是指针。例如, NSString *text
不应该用 NSString* text
或 NSString * text
。
推荐:
@interface RWTTutorial : NSObject
@property (copy, nonatomic) NSString *tutorialName;
@end
不推荐:
@interface RWTTutorial : NSObject {
NSString *tutorialName;
}
属性特性
属性特性使用注意:
推荐:
/// 不可变的正常用copy,如NSString, NSArray, NSDictionary
@property (copy, nonatomic) NSString *tutorialName;
/// 可变的必须要用strong,
@property (strong, nonatomic) NSMutableString *tutorialName;
/// IBOutlet正常使用weak
@property (weak, nonatomic) IBOutlet UIView *containerView;
/// 代码块也应该使用copy
@property (copy, nonatomic) void (^handleAction)(void);
不推荐:
@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic) NSString *tutorialName;
点语法
点语法是一种很方便封装访问方法调用的方式。当你使用点语法时,通过使用getter或setter方法,属性仍然被访问或修改。
使用点语法用来访问和修改属性,这样子会使代码更加简洁。
推荐:
NSInteger arrayCount = [self.array count];
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
不推荐:
NSInteger arrayCount = self.array.count;
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
常量
在定义一些常量的话,应该使用static
来定义,不应该使用#define
,除非显式地使用宏。
推荐:
static NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";
static CGFloat const RWTImageThumbnailHeight = 50.0;
不推荐:
#define CompanyName @"RayWenderlich.com"
#define thumbnailHeight 2
枚举类型
例如:
typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
RWTLeftMenuTopItemMain,
RWTLeftMenuTopItemShows,
RWTLeftMenuTopItemSchedule
};
typedef NS_ENUM(NSInteger, RWTGlobalConstants) {
RWTPinSizeMin = 1,
RWTPinSizeMax = 5,
RWTPinCountMin = 100,
RWTPinCountMax = 500,
};
不推荐:
enum GlobalConstants {
kMaxPinSize = 5,
kMaxPinCount = 500,
};
单例模式
单例对象应该使用线程安全模式来创建共享实例。
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
导入
如果有一个以上的 import 语句,就对这些语句进行分组。每个分组的注释是可选的。
注:对于模块使用 @import语法。
// Frameworks
@import QuartzCore;
// Models
#import "NYTUser.h"
// Views
#import "NYTButton.h"
#import "NYTUserView.h"