工程组 - iOS项目开发规范
-
语言
- OC
-
工具
- 编辑器:XCode 11.4(保持最新)
- 托管平台:Git(Sourcetree客户端)
- 三方类库管理:CocoaPods
-
代码
-
项目框架设计模式:MVP
-
UI界面开发:Interface Builder和纯代码混合开发
-
网络请求框架:AFNetworking
-
图片请求框架:SDWebImage
-
弹窗提示和加载圈效果:MBProgressHUD
-
刷新加载:MJRefresh
-
工程结构规范:
- 项目中物理文件和Xcode项目文件保持同步,
- 代码要按照类型进行分组,也要根据业务功能进行分组
- 工程中一般包含文件夹但不限于:category(分类)、util/helper(工具类)、resource(资源)、const(常量)、third(第三方)、define等。
-
注释规范:
- 如果方法、函数、类、属性等需要提供给外界或者他人使用,必须要加注释说明。
- 如果你的代码以SDK的形式提供给其他人使用,那么接口的注释是必须的。必须对暴露给外界的所有方法、属性、参数加以注释说明。
- 注释应该说明其作用以及注意事项
- 因为方法或属性本身就具有自我描述性,注释应该简明扼要,说明是什么和为什么即可。
-
常见代码编写规范:
-
类:每一个类文件名称,我们按照规范加上前缀,默认是以公司缩写作为前缀ZY(表示Zoneyet);减少类的继承层数,不超过3层,可以考虑使用category、protocol来代替继承;.h文件中只暴露出一些必要的类、公开的方法、只读属性;私有类、私有方法和私有属性以及成员变量,写在.m文件中
-
变量:变量命名使用有清晰描述性的方法名,如UIButton *deleteButtom,不要缩写或省略单词。(注:保证可读性的同时,for循环中遍历出来的对象或者某些方法的参数可以缩写)
-
常量:用常量来代替字符串字面值和数字,方便复用,可以快速修改而不需要查找和替换,用const来创建;
-
方法:方法名与方法类型 (-/+)之间应该以空格间隔,方法的命名也应该具有自我描述性,方法参数之前的单词要能描述参数的意义;
-
懒加载:当对象的创建依赖于其他对象,可能被使用也可能不被使用,并且这个对象创建需要经过大量计算或者比较消耗性能事,尽量重写 getter 方法以延迟实例化,而不是在 init 方法里给对象分配内存。
-
条件语句:不省略大括号(即使条件语句体中只有一行代码),条件语句中的条件不要直接和 YES 和 NO进行比较(如:禁止写if(xx == YES),或者if(xx == NO) ),nil 解析为 NO,YES 被定义为 1,所以没有必要在条件中与它进行比较;
-
枚举:使用 enum 时,使用
NS_ENUM()
定义,因为它有更强大的类型检查和代码补全功能; -
对象判等规范:如果不太清楚要比较的数据源的类型,使用isEqual:,因为isEqual会对参数进行类型检查,如果数据类型和receiver(方法调用者)类型不一致,它会返回NO。如果我们知道参数的确切类型,那么可以使用类似于isEqualToString:或者isEqualToArray:这样的方法,因为性能更好。
-
单例:慎重使用单例,避免产生不必要的常驻内存,单例初始化方法中尽量保证单一职责,尤其不要进行其他单例的调用。尽量是保证在全局中只有一份的对象,或者需要多线程访问的对象再使用单例。
-
委托:以触发消息的对象名开头,省略类名前缀并且首字母小写,如:
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row; - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
-
分类(延展):在 category 方法前加上自己的小写前缀以及下划线,避免在其他category中使用同名方法,例如:
@interface NSDate (ZYTimeExtensions) - (NSString *)zy_timeAgoShort; @end
-
组织代码:使用#pragma mark - 来做类内部代码组织以及方法分组。
-
-
IO规范:尽量少用NSUserDefaults,[[NSUserDefaults standardUserDefaults] synchronize] 会block住当前线程,知道所有的内容都写进磁盘,如果内容过多,重复调用的话会严重影响性能。建议一些经常被使用的文件做好缓存,避免重复的IO操作,只在合适的时候再进行持久化操作。
-
延迟调用规范:performSelector:withObject:afterDelay:要在有Runloop的线程里调用,否则调用无法生效,异步线程中默认没有runloop,可手动创建后在进行延迟调用。
-
工程公共工具类文件夹
-
创建Define文件夹,存放内容如下:
-
DataDefine.h文件:
存放宏定义数据状态码,如:
#define ERR_CODE_USER_LOGIN_USER_NOT_EXIST (14) //用户不存在 #define ERR_CODE_USER_LOGIN_PW_ERR (14) //密码错误 #define ERR_CODE_USER_CODE_MOBILE_EXIST (4) //手机号已注册 #define ERR_CODE_USER_CODE_MOBILE_NOT_EXIST (1010) //手机号不存在 #define ERR_CODE_USER_RESET_PW_TOKEN_INVALID (1018) //token失效 ......
存放一些错误文本信息,如:
// Error info #define ErrInfo_Network @"网络连接失败,请检查您的网络连接" #define ErrInfo_ServerInternal @"服务器内部错误" #define ErrInfo_Data @"数据错误" ......
存放固定秘钥信息,如:
#define API_SIGN_KEY @"%r3fd)&ds~23ds1+;xJL" #define RC4_SIGN_KEY @"%r3fd)&ds~23ds1+;xJL" ......
-
HTTPDefine.h文件:
存放请求参数配置,如:
//请求超时时间 #define TIMEINTERVAL_HTTP_URL_REQUEST (30.0F) #define TIMEINTERVAL_PIC_URL_REQUEST (60.0F) //缓存超时时间 #define TIMEINTERVAL_HTTP_EXPIRE1 (60*60) #define TIMEINTERVAL_HTTP_EXPIRE2 (60*60*24) //(60*60*24) //(1) #define TIMEINTERVAL_PIC_EXPIRE (1) //(60*60*24) //(1)
存放通用请求URL,通用请求参数名称,如:
// Base URL #define URL_TEST_BASE @"http://121.199.38.85/mishiclient/api.php?act=" #define URL_TEST_BASE_POST @"http://121.199.38.85/mishiclient/api.php?" #define URL_UPGRATE @"soft_upgrade" // Root #define URL_LOGIN @"login" // Login #define URL_ORDER_LIST @"get_order_list" // Order List
-
UIDefine.h文件:
存放UI界面常用数据信息,如:
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define SCREENH_HEIGHT [UIScreen mainScreen].bounds.size.height #define MAIN_SCREEN [UIScreen mainScreen] #define NAV_HEIGHT (44.0F)
存放常用的颜色设置:
//随机颜色 #define MyRandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0] //设置r g b颜色 #define RGBColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] #define RGBAColor(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(r)/255.0 blue:(r)/255.0 alpha:a] // clear背景颜色 #define GClearColor [UIColor clearColor]
自定义NSLog:
//项目开发中,需在很多地方Log,为方便发布的时要去掉Log,可进行自定义 #ifdef DEBUG #define debugLog(...) NSLog(@"%s 第%d行 \n %@\n\n",__func__,__LINE__,[NSString stringWithFormat:__VA_ARGS__]) #else #define debugLog(...) #endif
等等。
-
-
Utils类
-
存放常用的项目通用方法类Utils,如:
// 验证邮箱 + (BOOL)validateEmail:(NSString *)candidate { NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex]; return [emailTest evaluateWithObject:candidate]; } // 验证手机号 + (BOOL)validatePhoneNumber:(NSString *)checkString{ /** * 手机号码 * 移动:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188 * 联通:130,131,132,152,155,156,185,186 * 电信:133,1349,153,180,189 */ NSString * MOBILE = @"^1(3[0-9]|5[0-35-9]|8[0235-9])\\d{8}$"; /** 10 * 中国移动:China Mobile 11 * 134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188 12 */ NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d)\\d{7}$"; /** 15 * 中国联通:China Unicom 16 * 130,131,132,152,155,156,185,186 17 */ NSString * CU = @"^1(3[0-2]|5[256]|8[156])\\d{8}$"; /** 20 * 中国电信:China Telecom 21 * 133,1349,153,180,189,181 22 */ NSString * CT = @"^1((33|53|8[09])[0-9]|349)\\d{7}$"; /** 25 * 大陆地区固话及小灵通 26 * 区号:010,020,021,022,023,024,025,027,028,029 27 * 号码:七位或八位 28 */ // NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$"; NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE]; NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM]; NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU]; NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT]; if (([regextestmobile evaluateWithObject:checkString] == YES) || ([regextestcm evaluateWithObject:checkString] == YES) || ([regextestct evaluateWithObject:checkString] == YES) || ([regextestcu evaluateWithObject:checkString] == YES)) { return YES; } else { return NO; } } //检查密码中的特殊字符 + (BOOL)containSpecialCharacter:(NSString *)str { //***需要过滤的特殊字符:~¥#&*<>《》()[]{}【】^@/£¤¥|§¨「」『』¢¬ ̄~@#¥&*()——+|《》$_€。 NSRange specialCharacterRange = [str rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"~¥#&*<>《》()[]{}【】^@/£¤¥|§¨「」『』¢¬ ̄~@#¥&*()——+|《》$_€"]]; if (NSNotFound == specialCharacterRange.location) { return NO; } return YES; }
等等
-
-
BaseCode文件夹
通过OC语言的继承机制,利用已有的数据类型来定义新的数据类型,新的数据类型不仅拥有新定义的成员,还拥有旧的成员。
项目中可包含的项目基类不仅限于:
-
继承于UITabBarController,包含的功能:
- 设置tabBar的样式
- 初始化tabBarController控制的controllers
- 实现UITabBarControllerDelegate协议方法,在方法中实现项目通用逻辑,例如在用户第二次点击tabItem的时候,是否需要刷新界面的情况
- 注册并监听tabItem切换的消息
-
继承于UINavigationController
-
设置navigationBar的样式,可重写+ (void)initialize方法,在方法中定制样式来满足项目中多个UINavigationController的navigationBar样式一致,如果多个不同样式,可通过isKindOfClass来判断区分使用
-
设置返回手势
navigationController: didShowViewController: animated:
-
-
继承于UIViewController
-
界面的背景颜色设置
-
消息提示的方法:加载成功/失败,提交成功/失败,网络异常等。
-
-
继承于UITableViewCell/UICollectionViewCell:
-
在基类中写传值方法,子类继承时,直接实现即可:
- (void)configureWithItem:(id)item;
-
不同的页面可能会重复的利用一种cell 或者稍微变化, 这时只需再创建第二个基类, 可以将控件暴露在.h文件中,如果是传值的话, 就在.m中重写父类方法;更改frame的话, 可以在layoutSubviews里面更改,(使用[super layoutSubviews])
-
-
自定义视图,继承UIView,对于一些列表视图(tableView/CollectionView)的头视图、轮播图、时间选择器等, 需要自定义的视图, 需要传值的, 可以像cell一样,先写一个传值的方法备着。其他的视情况而定。
-
继承于系统控件,比如继承于UILabel/UIButton,自定义一些UI效果
-
继承于NSObject
- 用作model类,数据解析时, 有些属性以及容错方法都是重复率比较高的,可以创建一个基类。但是最好确定每个model都有这个属性再建立基类,如果没有,可以只写容错方法。
-
-
-
以上内容有些借鉴网络,如有侵权,请联系删除,qq: 772081405。
网友评论