# 我的 iOS 代码规范
[TOC]
***
参考资料:
- VV木公子:一份走心的iOS开发规范
https://www.jianshu.com/p/c818c00e0690
# 类型
使用到整形变量时,建议使用NSInteger NSUInteger,不建议使用int,uint 。
使用float时,建议使用CGFloat
# 常量
建议
```
static NSString *const PLMessageCountChanageNotificationName = @"MessageCountChanageNotification"
static NSUInteger const PLRetryMaxCount = 5
```
不建议
```
#define PLMessageCountChanageNotificationName @"MessageCountChanageNotification"
#define PLRetryMaxCount 5
```
# 变量
遵循驼峰模式即可
对于实例变量建议以下划线开始命名
```
@interface Foo() {
NSString *_name
}
@end
```
对于局部变量建议不要以下划线开头, 避免误解变量的作用域
不建议
```
- (void)uploadVideo {
NSString *_name = @"";
}
@end
```
# 字面值
对于NSString, NSDictionary, NSArray, 以及 NSNumber 支持语法糖
建议
```
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;
```
不建议
```
NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingStreetNumber = [NSNumber numberWithInteger:10018];
```
# 枚举
当使用 `enum` 的时候,建议使用新的固定的基础类型定义,因为它有更强大的类型检查和代码补全。 SDK 现在有一个 宏来鼓励和促进使用固定类型定义 `- NS_ENUM()`
建议
```
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear,
};
```
```
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
```
不建议
```
enum UIViewAnimationCurve {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear,
};
```
# 控制语句
## 关于if
### 一行代码:
条件语句体应该总是被大括号包围。尽管有时候你可以不使用大括号(比如,条件语句体只有一行内容),但是这样做会带来问题隐患。比如,增加一行代码时,你可能会误以为它是 if 语句体里面的。此外,更危险的是,如果把 if 后面的那行代码注释掉,之后的一行代码会成为 if 语句里的代码。
建议
```
if (!error) {
return success;
}
```
不建议
```
if (!error)
return success;
or
if (!error) return success;
```
多行代码:
在if中对于花括号`{`的处理应该趋于书写在行尾,这样控制条件和控制语句容易被视为一个整体。
建议
```
if(condition) {
//...
} else {
//...
}
```
不建议
```
if(condition)
{
//..
}
else
{
//..
}
```
### 尤达表达式
不要使用尤达表达式。尤达表达式是指,拿一个常量去和变量比较而不是拿变量去和常量比较。它就像是在表达 “蓝色是不是天空的颜色” 或者 “高个是不是这个男人的属性” 而不是 “天空是不是蓝的” 或者 “这个男人是不是高个子的”
![yoda](media/14988919579371/yoda.png)
推荐
```
if ([myValue isEqual:@42]) { ...
```
不推荐
```
if ([@42 isEqual:myValue]) { ...
```
### 多层嵌套
在使用条件语句编程时,不要嵌套 if 语句。使用多个 return 可以避免增加循环的复杂度,并提高代码的可读性。因为方法的重要部分没有嵌套在分支里面,并且你可以很清楚地找到相关的代码。
推荐
```
- (void)someMethod {
if (![someOther boolValue]) {
return;
}
//Do something important
}
```
不推荐
```
- (void)someMethod {
if ([someOther boolValue]) {
//Do something important
}
}
```
### 复杂的表达式
当你有一个复杂的 if 子句的时候,你应该把它们提取出来赋给一个 BOOL 变量,这样可以让逻辑更清楚,而且让每个子句的意义体现出来。
推荐
```
BOOL nameContainsSwift = [sessionName containsString:@"Swift"];
BOOL isCurrentYear = [sessionDateCompontents year] == 2014;
BOOL isSwiftSession = nameContainsSwift && isCurrentYear;
if (isSwiftSession) {
// Do something very cool
}
```
## 关于switch
括号不是必须的,为了代码结构层次清晰,建议加上括号。
```
switch(condition){
case 1:
{
//one line or multi-line
}
break;
default:
break;
}
```
对于枚举类型的switch,可以不需要default
```
UIViewAnimationCurve curveType = UIViewAnimationCurveEaseInOut;
switch(curveType) {
case UIViewAnimationCurveEaseInOut:
{
}
break;
case UIViewAnimationCurveEaseIn:
{
}
break;
case UIViewAnimationCurveEaseOut:
{
}
break;
case UIViewAnimationCurveLinear:
{
}
break;
}
```
## 关于for循环
对于集合类型(array,set) 建议使用 enumerateObjectsUsingBlock
```
NSArray *nameArray = @[@"Kita","jonas"];
[nameArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//...
}];
```
其次可以选择for in 如果不需要索引的话
```
for(NSString *name in nameArray) {
//...
}
```
## 三目运算符
三目运算符 `?` 应该只用在它能让代码更加清楚的地方。 一个条件语句的所有的变量应该是已经被求值了的。类似 if 语句,计算多个条件子句通常会让语句更加难以理解。或者可以把它们重构到实例变量里面。
推荐
```
result = a > b ? x : y;
```
不推荐
```
result = a > b ? x = c > d ? c : d : y;
```
# 属性
对于属性修饰符要全都指示出来,对于纯量类型默认是(atomic,assign),对于对象类型默认是(atomic,strong)。权限修饰符默认readwrite可以不写,一般情况下属性都是readwrite,对于只读属性需要写明readonly
对于有可变类型的类(NSString,NSArray,NSDictionary,NSSet) 建议使用copy,是因为有可能引用可变对象
建议
```
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) UIView *containerView;
```
不建议
```
@property(nonatomic,strong) NSString *name;
@property(nonatomic) UIView *containerView;
```
# 方法
方法类型(-/+)后需要空一格
建议
```
- (void)setTitle:(nullable NSString *)title forState:(UIControlState)state;
```
不建议
```
-(void)setTitle:(nullable NSString *)title forState:(UIControlState)state;
```
# 注释
文件注释
注释是代码可读性的关键,最好的代码应该自成文档。
其他注释(类注释,方法注释等)
xcode8 建议使用自带注释快捷键 command+option+/
# 代码结构组织
viewController类的建议
```
@property (nonatomic, strong) UITableView *tableView;
...
#pragma mark - Life cycle (生命周期)
- (instancetype)init {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}
- (void)dealloc {}
#pragma mark - UITableViewDelegate (代理协议)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {}
...
#pragma mark - LMFootViewButtonDelegate(代理协议)
-(void)footViewDidSelectedButton:(UIButton *)sender andIndex:(NSInteger)index andButtonTitle:(NSString *)titleText{}
...
#pragma mark - IBActions(event response)
- (IBAction)submitData:(id)sender {}
...
#pragma mark - Private Methods
- (void)privateMethod {}
...
#pragma mark - Getter and Setter
- (NSString *)name;
- (void)setName:(NSString *)name;
```
# 使用CGRect函数
建议
```
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
CGRect frame = CGRectMake(0.0, 0.0, width, height);
```
不建议
```
CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };
```
# Tips
## 行宽
尽量保持在100以内,具体设置如下:
>Xcode->Preferences->Text Editing->Page guide at column