文档说明
- 在APP开发过程中要严格遵守本文档制定的开发规范,如果特定开发平台的开发规范和通用开发规范出现冲突,以特定平台的开发规范为准。
- 除非特殊说明,驼峰式指小驼峰式,即第一个单词的字母小写,其余单词的首字母大写,其余字母小写,单词之间不以空格断开或连接号(-)、下划线(_)连接的写法,如:lowerCamelCase
- 除非特殊说明,大驼峰式(也叫帕斯卡式)指第一个单词前缀字母使用大写字母;后续单词的首字母亦用大写字母,单词之间不以空格断开或连接号(-)、下划线(_)连接的写法,如:UpperCamelCase、PascalCase
- 除非特殊说明,小写下划线式指全部字母小写,单词之间使用下划线(_)连接的写法,如:lower_underscore_case
- 除非特殊说明,大写下划线式指全部字母大写,单词之间使用下划线连接的写法,如:UPPER_UNDERSCORE_CASE
- 有可能进行修改或者增加
通用(Android、iOS)开发规范
文件相关规范
- 文件编码统一使用UTF-8
编码相关规范
- 不要忽略异常处理
- 缩进使用4个空格
- 变量命名使用驼峰式
- 方法命名使用和变量相同的格式
- 静态变量命名使用大写下划线式
- 变量使用名词命名,方法使用动词命名,使命名清晰易懂,避免使用缩写
- 方法之间空一行
- 代码块之间空一行
- IDE设置为100列自动断行
- 代码中不能出现中文或者拼音
- 删除不使用的、跟程序无关的代码(变量、方法、文件等)
- 遵守不要重复自己原则(Don’t repeat yourself)
- 除非特殊说明,把缩写当作普通单词,遵循以上写法
- 类、资源和变量按照适用范围从大到下,命名从短到长
- 类、方法后的大括号隔开一个空格即可,不用另起一行
- 在函数或者封闭空间内,不要随意直接使用全局变量,而是使用传参的方式
- 登录使用login,登出使用logout,均作为一个单词
- 将模型分为业务模型(网络请求模型)和本地模型(视图模型)
- 减少继承,增加复用
- 引入的第三方库必须再添加一层封装,这样在更换第三方库的时候不需要更改代码
- 能在方法内作为参数的变量绝不生命为全局变量
- 能在单个控制器声明的变量绝不声明为应用全局变量
- 每次提交版本控制,尽量提交较少的更改
Android开发规范
开发工具规范
- 开发工具统一使用Android官方推荐的Android Studio
- 更改编码风格设置,私有成员变量添加m前缀
- 使用Android Studio自带的Gradle进行依赖管理
- 更改文件头部信息,如图覆盖设置,统一使用姓名全拼或者中文
- 不要在module中引用其它module
文件相关规范
类文件使用
大写驼峰式
写法,如UserFragment,RootActivity资源文件使用
小写下划线式
写法,如fragmengt_user,activtiy_root菜单文件命名跟布局命名类似,匹配对应的组件
值文件命名规范为使用复数,如strings.xml
资源文件中的
变量
(name、id)采用驼峰式所有
xml文件
默认采用小写下划线式父类或基础模块命名为
base
模块之间不交叉使用独立文件定义的键值,直接在文件中定义。
使用独立文件放置跨文件(Fragment、Activity、UIViewController)的键值,其它键值否则定义在文件内。
字符串资源名称(name)前缀
类型 | 说明 | 前缀 | 例子 (name) |
---|---|---|---|
占位符 | placeholder | placeholderTitle | |
格式 | format | formatPrice | |
Activity标题 | activity | activityUser | |
按钮标题 | button | buttonSubmitOrder | |
带冒号的说明文字 | label | labelUserName | |
度量单位 | unit | unitDollor | |
符号 | symbol | symbolMinus | |
提示 | 用于EditText的hint属性 | hint | hintOptional |
标签 | tab | tabIndex |
- 跟状态相关的文件使用以下命名方式:
状态 | 后缀 | 例子 |
---|---|---|
默认 | _normal | button_login_normal.png |
按下 | _pressed | button_login_pressed.png |
获得焦点 | _focused | button_login_focused.png |
已禁用 | _disabled | button_login_disabled.png |
已选择 | _selected | button_login_selected.png |
- 图片文件命名规范:
类型 | 前缀 | 例子 | 说明 |
---|---|---|---|
标题图标 | ab_ | ab_stacked.png | |
普通按钮 | button_ | button_login_normal.png | |
对话框图标 | dialog_ | dialog_top.png | |
分隔线 | divider_ | divider_horizontal.9.png | |
普通图标 | icon_ | icon_star.png | |
菜单图标 | menu_ | menu_submenu_bg.9.png | |
通知图标 | notification_ | notification_bg.9.png | |
标签页图标 | tab_ | tab_home_selected.9.png | |
背景图 | background_ | background_user.png | |
占位图片 | placeholder_ | placeholder_goods_image.png | 因为有些图片需要请求网络,在获得网络图片资源之前,显示的图片叫占位图片 |
- 布局文件命名规范:
组件 | 类名 | 布局命名 |
---|---|---|
Activity | UserProfileActivity | activity_user_profile.xml |
Fragment | SignUpFragment | fragment_sign_up.xml |
Dialog | ChangePasswordDialog | dialog_change_password.xml |
AdapterView item | 无 | item_person.xml |
Banner | 无 | banner_guide.xml |
Partial layout | 无 | partial_title.xml |
- 键值对中的键命名规范
常见键值对 | 键命名前缀 |
---|---|
SharedPreferences | PREF_ |
Bundle | BUNDLE_ |
Fragment Arguments | ARG_ |
Intent Extra | EXTRA_ |
Intent Action | ACTION_ |
如:
// 注意,变量名和变量的值保持一致
static final String PREF_EMAIL = "PREF_EMAIL";
static final String BUNDLE_AGE = "BUNDLE_AGE";
static final String ARG_USER_ID = "ARG_USER_ID";
// Intent相关的键命名要包含完整的包名
static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";
编码相关规范
- 禁止统一处理不同的异常,如:
try {
someComplicatedIOFunction(); // may throw IOException
someComplicatedParsingFunction(); // may throw ParsingException
someComplicatedSecurityFunction(); // may throw SecurityException
} catch (Exception e) { // I'll just catch all exceptions
handleError(); // with one generic handler!
}
- 只引入必要的文件,使用import foo.Bar;而不是import foo.*;
- 私有非静态变量使用m前缀
- 私有静态变量使用s前缀
- 大括号下一行保留4个空格,如:
if (x == 1) {
x++;
}
- 折行代码保留8个空格
Instrument i =
someLongExpression(that, wouldNotFit, on, one, line);
- 覆盖父类的方法或者实现接口要在方法上方添加@Override注释
- 按照以下方式打印数据
Log.v(String TAG, String message);//详细
Log.d(String TAG, String message);//调试
Log.i(String TAG, String message);//信息
Log.w(String TAG, String message);//警告
Log.e(String TAG, String message);//错误
- 类成员采用以下顺序
- Constants(常量)
- Fields(成员变量)
- ButterKnife(绑定视图)
- Setter and getter (成员变量的setter和getter方法)
- Constructors(构造函数)
- Override methods and callbacks (public or private)(重写函数和回掉函数)
- Public methods(公有方法)
- Private methods(私有方法)
- Inner classes or interfaces(内部类或接口)
- 生命周期函数按照生命周期排序,如:
public class MainActivity extends Activity {
//Order matches Activity lifecycle
@Override
public void onCreate() {}
@Override
public void onResume() {}
@Override
public void onPause() {}
@Override
public void onDestroy() {}
}
- 在xml文件中,空元素要自己关闭,如
<TextView
android:id="@+id/fragment_user_username_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
iOS开发规范
开发工具规范
- 开发工具使用苹果官方的Xcode
- 开发工具必须从商店或官网下载,禁止复制未知来源的开发工具
- 使用http://alcatraz.io/管理Xcode第三方插件、主题和模板
- 使用https://cocoapods.org/和cocoapods-xcode-plugin进行依赖管理
- 电脑用户名设置为姓名全拼,Xcode会把这个值用在文件头部信息中
- 设置Organization和Class Prefix
- 尽可能使用const定义常量
- 按照Objective-C格式化风格进行格式化
编码相关规范
- 即使有命名空间限制,但是最好给每个组件都添加前缀
- 多个target 文件、公共方法(.h文件定义的方法)和变量要添加前缀
- 每个target中的每个类的每个方法只允许有一次
method swizzle
- 使用
#pragma mark - description
对代码分块,方便查阅 - 类文件命名禁止缩写
- 常量命名采用首字母大写的驼峰式,宏命名采用大写下划线式。使用static和const声明普通常量,使用#define声明宏,如:
static NSString * const CompanyName = @"The Company";
static const CGFloat ImageHeight = 50.0;
#define DEBUG_MODE = 1;
- 使用
.
号获取和设置属性,如:
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
而不是采用以下形式:
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
- 错误处理采用以下方法:
NSError *error;
if (![self trySomethingWithError:&error]) {
// Handle Error
}
而不是以下方式:
NSError *error;
[self trySomethingWithError:&error];
if (error) {
// Handle Error
}
- 使用
CGGeometry functions
获取CGRect
变量的属性,而不是直接访问,如:
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
而不是:
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;
- 常量使用以下方式定义:
static NSString* const CHECK_OUT_BUTTON_TITLE_FORMAT = @"去结算(%d)";
static CGFloat const SELLECT_ALL_BUTTON_TITLE_FONT = 12;
- 枚举类型使用以下方式定义:
typedef NS_EMUN(NSUInteger, LoginType) {
SELLER,
STORE_OWNER
};
即枚句类型的名称使用大写驼峰式的写法,值使用大写下划线式的写法
- 枚举类型使用按位掩码时,采用以下方式定义:
typedef NS_OPTIONS(NSUInteger, GoodsType) {
NEW_GOODS = 1 << 0,
HOT_GOODS = 1 << 1,
BEST_GOODS = 1 << 2
};
- 私有属性在类实现中定义,如:
@interface GoodsViewController ()
@property (nonatomic, strong) GADBannerView *googleAdView;
@property (nonatomic, strong) ADBannerView *iAdView;
@property (nonatomic, strong) UIWebView *adXWebView;
@end
- 不要直接和YES比较来判断是否为空或NO,采用以下方式:
if (!someObject) {}
if (someObject == nil) {}
if (isAwesome) {}
if (!someNumber.boolValue){}
if (someNumber.boolValue == NO){}
- 单例模式采用以下方法定义:
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
- 引入文件采用以下方式:
// Frameworks
@import QuartzCore;
// Models
#import "CommonUtil.h"
// Views
#import "CustomButton.h"
pchFile.h引入的文件必须引入该文件必要的所有.h文件,即使pchFile已经引入了这些.h文件
这样保证pchFile移除某些文件不会导致其他文件出现错误设计delegate时,第一个参数为发送信息的对象,如:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- 按照以下格式声明成员变量,如:
@property(nonatomic, strong) UIScrollView *scrollView;
总是使用
@property
声明变量,而不是在括号中UIViewController代码顺序
@property(nonatomic,strong)UIButton*button;
...
#pragma mark - life cycle
viewDidLoad
viewDidAppear
...
#pragma mark - UITableViewDelegate
#pragma mark - CustomDelegate
#pragma mark - event handlers
#pragma mark - private methods
#pragma mark - getters and setters
- 所有属性都使用getter和setter
- 所有View的初始化都放在getter中
在
viewDidload
里面只做addSubview和布局的事情,在viewDidAppear
里面做Notification的监听之类的事情。至于属性的初始化,则交给getter去做。 - 所有点击事件的添加都写在初始化getter中
- 使用代码生成视图
- 监听Notification后记得释放
- 约束写在updateViewConstraints中,例如
-(void)updateViewConstraints{
[super updateViewConstraints];
[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view).with.offset(20);
make.left.equalTo(self.view).with.offset(20);
make.right.equalTo(self.view).with.offset(-20);
}];
...
}