美文网首页
iOS新项目开发规范梳理(备忘)

iOS新项目开发规范梳理(备忘)

作者: ZhangMeng_ | 来源:发表于2020-03-31 18:06 被阅读0次

    工程组 - iOS项目开发规范

    1. 语言

      • OC
    2. 工具

      • 编辑器:XCode 11.4(保持最新)
      • 托管平台:Git(Sourcetree客户端)
      • 三方类库管理:CocoaPods
    3. 代码

      • 项目框架设计模式: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语言的继承机制,利用已有的数据类型来定义新的数据类型,新的数据类型不仅拥有新定义的成员,还拥有旧的成员。

          项目中可包含的项目基类不仅限于:

          1. 继承于UITabBarController,包含的功能:

            • 设置tabBar的样式
            • 初始化tabBarController控制的controllers
            • 实现UITabBarControllerDelegate协议方法,在方法中实现项目通用逻辑,例如在用户第二次点击tabItem的时候,是否需要刷新界面的情况
            • 注册并监听tabItem切换的消息
          2. 继承于UINavigationController

            • 设置navigationBar的样式,可重写+ (void)initialize方法,在方法中定制样式来满足项目中多个UINavigationController的navigationBar样式一致,如果多个不同样式,可通过isKindOfClass来判断区分使用

            • 设置返回手势

              navigationController: didShowViewController: animated:

          3. 继承于UIViewController

            • 界面的背景颜色设置

            • 消息提示的方法:加载成功/失败,提交成功/失败,网络异常等。

          4. 继承于UITableViewCell/UICollectionViewCell:

            • 在基类中写传值方法,子类继承时,直接实现即可:

              - (void)configureWithItem:(id)item;
              
            • 不同的页面可能会重复的利用一种cell 或者稍微变化, 这时只需再创建第二个基类, 可以将控件暴露在.h文件中,如果是传值的话, 就在.m中重写父类方法;更改frame的话, 可以在layoutSubviews里面更改,(使用[super layoutSubviews])

          5. 自定义视图,继承UIView,对于一些列表视图(tableView/CollectionView)的头视图、轮播图、时间选择器等, 需要自定义的视图, 需要传值的, 可以像cell一样,先写一个传值的方法备着。其他的视情况而定。

          6. 继承于系统控件,比如继承于UILabel/UIButton,自定义一些UI效果

          7. 继承于NSObject

            • 用作model类,数据解析时, 有些属性以及容错方法都是重复率比较高的,可以创建一个基类。但是最好确定每个model都有这个属性再建立基类,如果没有,可以只写容错方法。

    以上内容有些借鉴网络,如有侵权,请联系删除,qq: 772081405。

    相关文章

      网友评论

          本文标题:iOS新项目开发规范梳理(备忘)

          本文链接:https://www.haomeiwen.com/subject/dlrguhtx.html