前言
为什么要制定一套Objective-C在iOS APP开发的规范要求?我们都知道,一款APP开发出来之后,还有冗长的维护和迭代过程,而且在APP的开发过程中,绝大多数都是团队开发,如果在这期间没有一套统一、规范的开发标准,就很难保证代码风格的一致性,可读性降低 ,团队开发 和 后期维护 都会带比较严重的后果。
如果在APP的开发过程中都以这个标准去执行,代码的可读性、开发期间的沟通、后期维护都会非常顺畅。
开发标准(规范)制定依据
既然是标准,可能就会有人质疑了,你制定的这套标准有什么依据?
首先这个标准不是由个人制定,也不是由哪一个团队制定,而是根据Apple官方文档以及Xcode 中提供的一些SourceCode 为参考来制定的。
当然还有很多认可度极高的文档:
The Objective-C Programming Language
Cocoa Fundamentals Guid
Coding Guidelines for Cocoa
iOS App Programming Guide
规范正文
一 . 关于命名
命名要求含义清楚,尽量做到不需要注释也能了解其作用;
不要偷懒,勤加注释;
命名使用英语,不要使用拼音、数字。
1. 类的命名
大驼峰式命名:每个单词的首字母都采用大写字母。
前缀以约定的标志性字母开头,中间以功能英文单词命名,再加上全名后缀(不得简写)。
例一:GTHomePageViewController // Controller层控制器类名
例二:GTUserInfoModel //Model层类名
例三:GTNewsListsTableViewCell //View层TableViewCell的命名
例三:GTAlertSheetViewDelegate //代理方法中Delegate的命名
例三:GTAlertSheetViewDateSource //代理方法中DateSource的命名
2. Foundation成员变量的命名
小驼峰式命名:第一个单词以小写字母开始,后面的单词的首字母全部大写。
例一: .m 文件中声明的私有变量
{
NSString * _somePrivateVariable;
}
例二:property变量
@property (nonatomic, strong) NSString *userName;
3. UIKit成员变量的命名
小驼峰式命名:第一个单词以小写字母开始,后面的单词的首字母全部大写。此外命名必须是 描述性的单词+变量类型,一目了然。
变量类型运行使用通用的缩写,若缩写不是公认的,不推荐。
例一: .m 文件中声明的私有变量
{
UILabel * _nameLabel;
UIButton * _nameBtn
}
例二:property变量
@property (nonatomic, strong) UILabel * nameLb;
@property (nonatomic, strong) UIButton * nameButton;
4. 宏命名
- 情况一:全部大写,单词间用 _ 分隔。[不带参数] [不推荐使用]
- 情况二:以字母 k 开头,后面遵循大驼峰命名。[不带参数]
- 情况三:以字母 k 开头,小驼峰命名。[带参数]
推荐 使用 [情况二] 和 [情况三]。
例一:情况一
#define THIS_IS_AN_MACRO @"THIS_IS_AN_MACRO"
例二:情况二
#define kWidth self.frame.size.width
例三:情况三
#define kGetImageUrl(url) [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",kBaseUrl,url]]
5. Xib的命名
Xib文件的命名与其对应的.h文件保持相同
二. 枚举Enum
为什么要把枚举单独拿出来说?
我们都知道,代码中很多需要根据状态值来进行分类的,比如服务器传来一个状态参数1 、2、 3等等值,1代表交易成功、2代表已经付款、3代表未付款等等,这里我们在代码编写过程中直接用if else 来分类就low爆了,不仅代码的可读性低,而且维护起来非常不便。而且如果状态值代表的意义还有改变的,需要来怎么去处理?如果开发初期就规定使用枚举,这些问题就会很容易的解决。
- 必须使用 NS_ENUM 或者 NS_OPTIONS
- Enum类型的命名与类的命名规则一致
- Enum中枚举内容的命名需要以该Enum类型名称开头
typedef NS_ENUM(NSUInteger, ShareUISelcetIndex) {
ShareUISelcetIndexDefault = SSDKPlatformTypeUnknown, // 默认
ShareUISelcetIndexWechatFriend = SSDKPlatformSubTypeWechatSession, // 微信好友
ShareUISelcetIndexWechatGroup = SSDKPlatformSubTypeWechatTimeline, //微信朋友圈
ShareUISelcetIndexQQFriend = SSDKPlatformSubTypeQQFriend, //QQ好友
ShareUISelcetIndexQQZone = SSDKPlatformSubTypeQZone, //QQ空间
ShareUISelcetIndexSina= SSDKPlatformTypeSinaWeibo, //新浪
ShareUISelcetIndexRefresh, // 刷新
ShareUISelcetIndexCopyToPad, // 复制到剪切板
};
三. 方法的命名
1.普通方法的命名
方法使用小驼峰法命名。
一个规范的方法读起来应该像一句完整的话(OC语言的风格)。读过之后便知函数的作用。
执行性的方法应该以动词开头,小写字母开头。
返回性的方法应该以返回的内容开头。
例一:执行性
-(void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
例二:返回性
-(instancetype)arrayWithArray:(NSArray *)array;
2.Delegate方法的命名
- 类的实例必须为回调方法的参数之一;
- 回调方法的参数只有类自己的情况,方法名要符合实际含义;
- 以类的名字开头(回调方法存在两个以上参数的情况)以表明此方法是属于哪个类的;
- 推荐使用did和will通知Delegate已经发生的变化或将要发生的变化.
类的实例必须为回调方法的参数之一
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
回调方法的参数只有类自己的情况,方法名要符合实际含义;
-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
以类的名字开头(回调方法存在两个以上参数的情况)以表明此方法是属于哪个类的
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
推荐使用did和will通知Delegate已经发生的变化或将要发生的变化.
-(NSIndexPath*)tableView:(UITableView*)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath;
-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath;
3. 对方法进行分组(#pragma mark -)
使用 #pragma mark - 方式对类的方法进行分组,会使代码分区,看起来非常赏心悦目。
如图:
4. 代码缩进
[小技巧]直接强文件中的代码剪切,再复制粘贴进来。 Xcode 会自动对代码进行缩进处理。
Method与Method之间至少空一行,最好是最多也只空一行。
5. 大括号写法
- 左括号跟在第一行后边
- 任何需要写大括号的部分,不得省略
错误示例:
- (void)wrongExample{
BOOL someCondition = YES;
if (someCondition)
NSLog(@"this is wrong!!!");
}
规范示例:
- (void)rightExample{
BOOL someCondition = YES;
if (someCondition){
NSLog(@"this is wrong!!!");
}
}
四. 注释
1. 属性注释
- 推荐使用 注释统一采用文档注释方式:/** description */ ,即Xcode 8 提供的快捷键注释。Xcode 7 版本采用这种注释在调用该属性的时候,会提示出这个描述,但现在Xcode 8 似乎没有。
- 其他注释 // Description
@interface ShareUIView : UIView
/**
block one
*/
@property (nonatomic,copy) void(^cellClickblock)(ShareUISelcetIndex index);
@property (nonatomic,copy) void(^cellPushblock)(ShareUISelcetIndex index); // block two
@end
2. 方法声明注释
- 推荐使用 Xcode 8 提供的快捷键注释。
/**
单例模式
*
@return 单例对象
*/
+(LeeAlertSheetView *)sharedInstacne;
/**
* 创建提示框(Alert 可变参数版)
*
* @param title 标题
* @param message 提示内容
* @param cancelTitle 取消按钮(无操作,为nil则只显示一个按钮)
* @param vc VC iOS8及其以后会用到
* @param confirm 点击按钮的回调(取消按钮的Index是cancelIndex -1)
* @param buttonTitles 按钮(为nil,默认为"确定",传参数时必须以nil结尾,否则会崩溃)
*/
- (void)showAlert:(NSString *)title message:(NSString *)message cancelTitle:(NSString *)cancelTitle viewController:(UIViewController *)vc confirm:(myAlertSheetViewBlock)confirm buttonTitles:(NSString *)buttonTitles, ... NS_REQUIRES_NIL_TERMINATION;
五. 三目运算符
我们直接就开始举个栗子了
- (void)rightExample{
BOOL someCondition = YES;
if (someCondition){
self.myView.alpha = 0.5;
}else{
self.myView.alpha = 0.1;
}
}
这里如果用三目运算符怎么写?
- (void)rightExample{
self.myView.alpha = someCondition ? 0.5: 0.1
}
六. 多使用常量(const),代替宏(define)
可以参考这篇文章iOS 宏(define)与常量(const)的正确使用
比如定义一个常量又不想被修改应该这样:
static NSString * const HSCoder = @"汉斯哈哈哈";
static NSString * const collectionCellIdentifier = @"ShareUICollectionViewCell";
七. 其他
- 在属性命名中,如果类的全名太长,可以使用一些缩写,但这些缩写必须是大家公认,没有任何歧义的。(比如:nav,bg,btn,lb,tf等)。
- 在函数命名中,推荐使用一些经典的操作应该使用约定的动词,如initWith,insert,remove,replace,add等等。
- 对于类的method: 左括号另起一行写(遵循苹果官方文档)。这一要求可以使用,但不强制使用,具体可以根据团队开发要求来限定,因为比如我们创建一个UIViewController,里面的方法均没有执行这一要求,所以我们也不强制执行。
如有纰漏,欢迎留言狂喷
没有伤害,就没有进步。
- QQ 375701847。