最近在整理代码,所以将以前积累的一些代码规范方面的知识分享出来,希望能对大家编码时有所帮助。一个好的代码风格的重要性,不言而喻,希望大家能重视。
下面是小编在平时积累的,肯定不全面,希望大家积极评论,一起完善。
推荐文档:
https://github.com/oa414/objc-zen-book-cn
https://github.com/onefboy/CodeSpecification
一:工程目录结构规范
1、除了第三方框架中出现警告(也要极力消除警告),代码中不能出现警告。
2、除了注释外,所有的资源命名都用英文,不要用魔术数字、汉字。
3、推荐一个规范的工程目录结构
Macro:存放公用头文件比如:URL,宏定义,通知,枚举等等。
Storage:存放封装HTTP请求和数据库操作文件。
Resources:存放html、音频、视频、图片等资源文件。
Extra:存放第三方SDK,如:百度地图SDK,支付宝SDK等等
Vendors:存放工程中封装的一些公用方法 或 SDK。
Control:存放网络请求(HTTP)Manager、数据库(DB)操作等类文件。
View:存放所有自定义界面View。
Model:负责解析HTTP下来的数据。
Controller:存放所有控制器类。
4、所有的ViewController都应继承自一个BaseViewController(大家懂的)。
5、文件命名、类名应以相应模块英文单词为准,不要用魔术数字命名,比如:
6、所有的公用类头文件声明,放在一个.h头文件里面(比如:宏定义、枚举、URL、第三方账号、一些公用配置参数)。
7、所有第三方账号都用宏定义表示,方便修改、维护。
8、StoryBoard使用:界面跳转用代码实现,不用拖关系线条,方便后期维护。
9、界面适配,建议用Auto Layout放弃Autoresizing,随着大屏iPhone推出,苹果主推Auto Layout技术。
10、所有的类名和主要方法,要加注释。
11、所有的公用方法,都抽成一个公用类里。
12、不要用虚拟目录,如果需要在工程中添加新的文件夹,使用 Add File To 方法添加。
二:代码规范
1、声明类或方法时,注意空格的使用,参数过多时可换行保持对齐。
- (void)registerWithUserName:(NSString *)userName
passowrd:(NSString *)password
code:(NSString *)code;
2、调用方法时也是如此,参数都写在一行或换行冒号对齐,
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"确认注册?"
delegate:nil
cancelButtonTitle:@"取消"
otherButtonTitles:@"确认", nil];
3、命名规则
类名首字母大写,方法名首字母小写,方法中的参数首字母小写,同时尽量让方法的命名读起来像一句话,能够传达出方法的意思。
4、变量名小写字母开头,常用驼峰命名,如:userName。
5、写 delegate 的时候类型应该为 weak 弱引用,以避免循环引用,当 delegate 代理的对象不存在时,delegate 没有抢引用对象也就销毁了。
@protocol LoginDelegate
- (void)login;
@end
@interface Delegate : UIViewController
// 使用 weak 弱引用,避免循环引用
@property (weak, nonatomic) id delegate;
@end
6、建议使用“#pragma mark”,方便阅读代码。
#pragma mark - Register Method
7、不要使用魔术数字命名
@property (strong, nonatomic) UIButton *oneButton;
@property (strong, nonatomic) UIButton *twoButton;
8、属性命名不要使用下划线命名方式, 使用驼峰风格。与系统保持一致
// 错误命名
@property (strong, nonatomic) NSString *end_time;
// 正确命名
@property (strong, nonatomic) NSString *endTime;
9、枚举类型的命名规则和函数的命名规则相同:命名时使用驼峰命名法,勿使用下划线命名。
typedef NS_ENUM(NSUInteger, LoginformType) {
LoginformTypeTel = 1,
LoginformTypeEmail = 2,
LoginformTypeSinaWeibo = 3,
LoginformTypeWechat = 4,
LoginformTypeQQ = 5,
};
10、一些非负数整形的数据建议用NSUInteger
@property (assign, nonatomic) NSUInteger age;// 年龄
11、头文件的引用:将系统头文件放在前面,自定义的头文件放在后面,中间可以换行。
##import <UIKit/UIKit.h>
#import "MemberVariable.h"
12、定义的变量要使用,不然会有警告,不要忽视这样警告.
13、关于大括号,代码块的使用,:
大括号内的对象是有生命周期的,对象的作用域在大括号里,出了大括号里面的对象就被释放掉了。
巧妙的使用大括号,可以使得代码更清晰整洁、高效。
14、三个叹号或者问号可以着重标记,可以方便快速查找
// !!!: 宏的使用
// ???: 方法的调用
15、变量命名规则
- 字符串后加 Str
- 集合后加 Array
- 字典后加 Dict
- Label后加 Label
- UIImageView后加 Img
- UIImage后加 Image
- 这时你会发现规律,在变量名后加的都是类型说明符的后缀。
16、 除了初始化方法(init、initWithCoder等)、dealloc方法和自定义的 setters 和 getters 内部,应避免直接访问实例变量。
// ---------------------- VC方法规范 ----------------------
* 1.第一区块viewDidLoad等方法
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewWillAppear:(BOOL)animated {}
- (void)viewDidAppear:(BOOL)animated {}
- (void)viewWillDisappear:(BOOL)animated {}
- (void)viewDidDisappear:(BOOL)animated {}
#pragma mark - Private Methods
- (void)register {
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier<#@"reuseIdentifier"#> forIndexPath:indexPath];
// Configure the cell...
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// do something
}
#pragma mark - CustomeDelegate
-(void)didSelectView....
#pragma mark - Event Action
-(IBAction)buttonDidTouchUpInside:(id)sender{}
#pragma mark - Getters And Setters
17、条件判断
BOOL isLogIn;
if (isLogIn == YES) {// 反对
NSLog(@"登录成功!");
}
if (isLogIn == YES) // 反对
NSLog(@"登录成功!");
if (isLogIn) {// 推荐
// 登录成功
}
if (!isLogIn) {// 推荐
// 登录失败
}
18、在方法签名中,在 -/+ 符号后应该有一个空格,方法片段之间也应该有一个空格。
- (void)loginWithUserName:(NSString *)userName passowrd:(NSString *)password;
+ (void)loginWithUserName:(NSString *)userName passowrd:(NSString *)password;
19、变量声明
@interface MemberVariable ()
{
// NSArray *_dataList;// 反对
}
// 推荐
@property (strong, nonatomic) NSArray *dataList;
20、变量限定符
当涉及到在 ARC 中被引入变量限定符时,限定符 (__strong, __weak, __unsafe_unretained, __autoreleasing) 应该位于星号和变量名之间,如:NSString * __weak text。
21、字面量(快速创建)
每当创建 NSString, NSDictionary, NSArray,和 NSNumber 类的不可变实例时,都应该使用字面量。要注意 nil 值不能传给 NSArray 和 NSDictionary 字面量,这样做会导致崩溃。
推荐:
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @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 *buildingZIPCode = [NSNumber numberWithInteger:10018];
22、当访问一个 CGRect 的 x, y, width, height 时,应该使用CGGeometry 函数代替直接访问结构体成员。
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
// 不推荐
CGRect frame2 = self.view.frame;
CGFloat x2 = frame.origin.x;
CGFloat y2 = frame.origin.y;
CGFloat width2 = frame.size.width;
CGFloat height2 = frame.size.height;
23、如果一个 BOOL 属性名称是一个形容词,属性可以省略 “is” 前缀,但为 get 访问器指定一个惯用的名字,例如:
@property (assign, getter=isEditable) BOOL editable;
24、单例对象应该使用线程安全的模式创建共享的实例。
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
26、Xcode 工程
为了避免文件杂乱,物理文件应该保持和 Xcode 项目文件同步。Xcode 创建的任何组(group)都必须在文件系统有相应的映射。为了更清晰,代码不仅应该按照类型进行分组,也可以根据功能进行分组。