美文网首页
iOS开发代码规范

iOS开发代码规范

作者: 永不止步的旅行者 | 来源:发表于2018-09-25 14:52 被阅读0次

    版本:1.0
    时间:2018年9月20日

    1.命名规范

    1.1. 属性、数据类型命名规范

    1.1.1. 声明的属性和实例变量
    • 驼峰命名,控件必须使用简写作为 前缀/后缀
    控件类型 前缀 demo
    UIView v__ vHome
    UILabel lbl__ lblName
    UIButton btn__ btnHead
    UITextField txf__ txfName
    UITextView txv__ txvSuggest
    UIImage img__ imgHead
    UIImageView imgv__ imgvHead
    UIScrollView scv__ scvHome
    UITableView tv__ tvHome
    UITableViewCell __Cell orderCell
    UICollectionView cv__ cvHome
    UICollectionViewCell __Cell orderCell
    UICollectionReusableView crv__ crvHeader
    UISlider __Slider nightShiftSlider
    UISwitch __Switch nightShiftSwitch
    UIActivityIndicatorView aiv__ aivNet
    UISegmentedControl __Sc optionsSc
    UIProgressView pv__ pvWebContent
    UIPageControl pc__ pcBanner
    UIViewController vc__ vcHome
    UITableViewController tvc__ tvcHome
    UICollectionViewController cvc__ cvcHome
    UITabBarController tbc__ tbcMain
    UIDatePicker __DatePicker receiveDatePicker
    UIPickerView __PickerView areaPickerView
    UIebView/WKWebView wv__ wvMain
    1.1.2 BOOL类型属性命名
    • 需要指定getter方法、属性名中不要带is、has、had、have,例如:
    @property (assign, getter=isEditable) BOOL editable;   
    
    1.1.3 常量命名
    • 不要使用魔法数字,就是1.2.3.4...。如果是一组有相近意义的数字,那么定义为枚举,如果只有单个或没有相近意义,那么定义为常量数字。
    代码 评价
    if errorCode == 10096 ... 后续维护人员怎么可能知道10096是什么含义?改动起来也很麻烦
    static NSInteger const kOverTimeErrorCode = 10096; if errorCode == kOverTimeErrorCode; 很好,kOverTimeErrorCode 常量有自身的意义,又代表了实际值10096
    • 使用const修饰常量,如果只在一个文件中使用,那么开头使用static修饰。例:
    static NSInteger const kOverTimeErrorCode = 10096;    
    
    • 不要使用宏定义常量
    • 定义宏的时候前缀和后缀不要使用双下划线,如:MACH,因为编译器定义的宏都是以双下划线作为开头和结尾的。
    • 定义给外部使用的常量,在.h文件中使用 UIKIT_EXTERN 或 FOUNDATION_EXPORT 修饰。例:
      // .h
      UIKIT_EXTERN NSString *const UITableViewIndexSearch;
      // .m
      NSString *const UITableViewIndexSearch = @"_UITableViewIndexSearch";       
    
    1.1.4 通知常量的命名
    • 通知常量的命名规则,[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification
    代码
    NSApplicationDidBecomeActiveNotification
    NSWindowDidMiniaturizeNotification
    NSTextViewDidChangeSelectionNotification
    NSColorPanelColorDidChangeNotification
    1.1.5异常常量的命名
    • 异常常量的命名规则:[Prefix] + [UniquePartOfName] + Exception
    代码
    NSColorListIOException
    NSColorListNotEditableException
    NSDraggingException
    NSFontUnavailableException

    1.2代码命名规范基础

    1.2.1 一般原则

    1.2.1.1 清晰性:
    • 方法清晰又简洁那是最好不过了,但是不应该为了简洁性而降低了清晰性,清晰性才是第一☝️。例:
    代码 评价
    insertObject:atIndex: 很好
    insert:at: 不清晰,insert 什么东西? at了什么?
    removeObjectAtIndex: 很好
    removeObject: 很好
    remove: 不清晰,移除了什么呢?
    • 在一般情况下不要缩写,把他们拼写出来
    代码 评价
    destinationSelection 很好
    destSel 不够清晰,不知道做什么
    setBackgroundColor: 很好
    setBkgdColor: 不清晰
    • 也许你觉得你的缩写是很普遍的,大家都知道的,然而并不是。因为大家的英语水平是参差不齐的。
    • 但是有些缩写是官方的,很普及,如:HTML、PPT,这些可以放心大胆的使用
    • 避免API名称中的歧义
    代码 评价
    sendPort 这是代表“发送到端口”(动词),还是代表“发送端口”(名词)
    displayName 是“显示名字”(动词),还是“需要显示的名字”(名词)
    1.2.1.2 一致性
    • 和cocoa 的编码规范保持一致性,如果你在命名的时候不确定,可以先去翻翻cocoa的头文件作为参考
    • 当一个方法使用多态时,一致性非常重要。在不同类(继承体系)中,做相同事情的方法应该有相同的名字(这也是多态的必要条件)
    1.2.1.3 命名中不要重复描述
    • 命名中不要重复描述自己
    代码 评价
    NSString 很好
    NSStringObject 重复描述了,不好
    • 常量、掩码值可以重复描述自身,比如通知常量。
    代码 评价
    NSUnderlineByWordMask 很好
    UIApplicationWillEnterForegroundNotification 很好

    1.2.2 前缀

    • 通用性极高的控件,使用项目名开头,如(AL,JCY)

    1.2.3 方法首字母规定

    • 方法名首字母小写,特殊名称除外,如:HTML、PDF 等
    • 每个参数的首字母小写:
    代码 评价
    fileExistsAtPath:isDirectory: 很好
    FileExistsAtPath:FsDirectory: 不好,跟苹果的规范不一致
    • 首字母不要使用_开头,因为不知道哪一天苹果爸爸的私有方法就被你给覆盖了

    1.2.4类和协议名

    • 类名必须代表该类含义的名称
    • 如果一个协议和任何类都没有联系的话,这个类可以用...ing结尾,与类作区分,如NSCoding, NSCopying等
    代码 评价
    NSLocking 很好,看起来就知道是个协议
    NSLock 不好,看起来感觉就是一个类
    • 如果一个协议与某个类相关联,那么这个协议就以【类名+协议名】作为整体协议名,如:UITableViewDelegate

    1.2.5 头文件

    • 如果一个协议和任何类都没有联系的话,将这个协议单独作为一个文件
    • 如果有几个类、协议相互关联的话,可以放入头一个头文件中
    代码 评价
    NSString.h NSString和NSMutableString都在里面
    NSLock.h NSLocking协议、NSLock、NSConditionLock、NSRecursiveLock都在里面
    • 如果是一个框架、那么都需要有一个头问件,以框架命名,包括框架所有的公共头文件,如:UIKit.h
    • 如果是一组相关的常量、函数、结构体、枚举等其他数据类型,可以放入一个公共的头文件中

    1.3方法命名

    1.3.1 通用规则

    • 方法名首字母小写(特殊名称除外:如HTML,PDF 等)
    • 每个参数的首字母小写
    • 如果方法代表对象要做的事情,那么以动词作为方法开头。但是不要使用do或者does作为开头,因为没有意义,当然也没有必要给动词新增形容词,比如:【使劲去解析】。。。
    • 如果方法是返回一个属性,那么方法名可以直接使用该属性相关的名词,不要在方法开头添加“get”等动词。
    代码 评价
    - (NSSize)cellSize; 很好
    - (NSSize)calcCellSize; calculate没有必要
    - (NSSize)getCellSize; get没有必要
    • 在所有参数之前使用关键词:
    代码 评价
    - (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag; 很好
    - (void)sendAction:(SEL)aSelector :(id)anObject : (BOOL)flag; 第二个和第三个参数都没有关键词,看不懂
    • 参数前的关键词是要经过描述的关键词,而不是不相关的关键词
    代码 评价
    - (id)viewWithTag: (NSInteger)aTag; 很好,WithTag明确描述了这个参数
    - (id)taggedView:(int)aTag; 不好,:aTag之前没有描述这个参数,而是taggedView,这与aTag是不符的
    • 新增一个比原方法更多参数的方法时,将新增的参数排列在原方法的参数后面
    代码 评价
    - (instancetype)initWithFrame:(CGRect)frameRect; 原方法
    - (instancetype)initWithFrame:(CGRect)frameRect name: (NSString *)name 新增了一个参数,紧跟在后面,很好
    • 不要使用and去链接两个描述属性的参数
    代码 评价
    - (int)runModalForDirectory:(NSString *)path file:(NSString *) name types: (NSArray *)fileTypes; 很好
    - (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes; and 没有必要
    • 如果一个方法用来描述两个独立的操作,使用“and”链接
    代码 评价
    - (BOOL)openFile:(NSString *)fullPath withApplication: (NSString *)appName andDeactivate:(BOOL)flag; 这个and用来代表连个独立的操作,可以使用

    1.3.2访问方法

    • BOOL值的属性不要使用is、has、had、have开头,指定getter方法为is、has、had、have开头
    • 只有对需要返回多个参数的方法时,才使用get。(多个参数,使用指针作为返回)
      代码|评价|
    • (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase;|多个返回参数使用get

    1.3.3代理方法

    • 以产生事件的类名开头(去掉前缀,第一个字母小写)
    代码 评价
    - (BOOL)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath 以tableView开头
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 以application开头
    • 如果只有一个标志发送对象参数,则拼接到方法最后
    代码 评价
    - (void)applicationWillResignActive:(UIApplication *)application 以application开头,参数拼接到最后
    • 在代理方法中通过添加will、did来修饰事件发生的时机

    1.3.4方法参数

    • 在方法中不要包含poiner 或 ptr
    • 避免使用1个字母或者两个字母参数
    • 不要使用缩写作为参数

    1.3.5私有方法

    • 不要使用下划线作为私有方法的前缀
    • 如果一定要添加前缀,可以使用【项目名字母缩写_】作为前缀

    1.4函数命名

    1.4.1 当一个方法中涉及的对象始终时单例对象,或者不涉及任何对象时,请使用函数,不要使用类方法/对象方法。

    1.4.2函数命名规则

    • 函数用类和常量相同的类型开头
    • 一般函数名称中包含描述描述函数的作用动词:
    代码
    CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
    NSDecimalCompact(NSDecimal *number)
    • 如果函数返回第一个参数的属性,则省略动词
    代码
    unsigned int NSEventMaskFromType(NSEventType type)
    float NSHeight(NSRect aRect)
    • 如果函数是使用引用来进行返回数据,则使用get
    const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)
    

    2.通用缩写

    2.1苹果中常用的缩写

    缩写 全写
    alloc Allocate
    alt Alternate
    app Application
    calc Calculate
    dealloc Deallocate
    func Function
    horiz Horizontal
    info Information
    init Initialize
    int Integer
    max Maximum
    min Minimum
    msg Message
    nib Interface Builder archive.
    pboard Pasteboard
    rect Rectangle
    Rep Representation
    temp Temporary
    vert Vertical

    2.2 一些比较有名气的缩写

    缩写
    ASCII
    PDF
    XML
    HTML
    URL
    RTF
    TIFF
    HTTP
    JPG
    PNG
    GIF
    LZW
    ROM
    RGB
    CMYK
    MIDI
    FTP

    3.开发框架的一些技巧和规范

    3.1 initialization类方法

    • 这个方法里一般可以设置类的版本号
    • 运行时会想类的继承链上的所有类发送initialize消息,所以肯能导致一个类的initialize方法被调用多次(因为子类没有实现,只能往上查找)
    • 可以使用dispatch_once 来只执行一次,也可以使用if (self == [NSFoo class]) {...}来执行指定逻辑
    • 不要显示调用initialize方法,如果你需要第一次触发一个类的initialize方法,你可以这样[UIImage self] 。

    3.2版本和兼容性

    *当为你的类新增了一些类或者方法,通常没有必要为每个类指定版本号。可以使用 respondsToSelector: 来兼容新老版本。

    4.文件规范

    4.1 .h文件

    • 类的.h文件不要暴露不必要属性与实例变量
    • 类的.h文件在引用的时候,非必要的文件使用@class声明类,不要使用import
    • 协议如果是需要给外部使用者知晓的,如NSCoping,则在.h文件中声明,否则只在.m中文件中声明
    • .h中,方法的参数、返回值如果是对象,则在参数和返回值里加入nullable / nonnull修饰符,指明返回值/参数是否可能为空
    • 公开的属性,如果外界不能更改,请使用readonly修饰,在.m的扩展。中再使用readWrite重新声明(readWrite可以省略)
    • .h中方法参数个数超过三个,或者方法过长影响阅读时,每个参数换行显示,以:(冒号)对齐。
    • 公开方法如果不是一眼能看明白,那么要添加注释,快捷键:command + option + /
    • 注释中写明特殊情况,如:如果发生错误,那么error = kNetWrong
    • .h中对公开的常量进行声明

    4.2 .m文件

    • 文件行数尽量控制在500行内,否则考虑重构
    • 方法分类
    方法分类
    #pragma mark - class methods
    #pragma mark - life cycle methods
    #pragma mark - public methods
    #pragma mark - event methods
    #pragma mark - update and animation UI methods
    #pragma mark - sdk Delegate
    #pragma mark - customDelegate method(如:#pragma mark - UITableViewDelegate method,这样cmd+左键点击UITableViewDelegate就能进入这个协议所在的文件,很方便查看)
    #pragma mark - private method(私有方法)
    #pragma mark - messageHandle (观察者处理)
    #pragma mark - getters and setter method
    • .m中对所有的#import"头文件"进行分类处理
    #import
    //系统头文件
    // ViewController
    // View
    // ViewModel
    // Model
    // API
    // Manager
    // Category
    • Setter / getter方法尽量写在.m 文件的最下面,因为你每次滚动文件的时候肯定不想看到他们
    • 两个方法之间空一行(注释为开头行)
    • 方法中的switch (enumType) 不要加default:分支,因为未来在这个enumType加了一种类型的时候,编译器会在这个switch的地方警告提示
    • 一个方法的行数尽量不要超过一个屏幕的高度。大约40~50行
    • 扩展中定义的属性,相同类的尽量写在一起。如UI类的属性放在一起,data类的放在一起
    • 一个方法只做一件事
    • 一个方法尽量能够不依赖全局变量或属性做事情(函数式比编程思想,具体可以去了解一下)
    • 方法中的特殊业务/边界判断,请注释

    5.其他

    • 若if/while 等判断里的条件比较多或者比较长的时候,在逻辑运算符之前换行
    if (job.JobState == JobState.New
          || job.JobState == JobState.Submitted
          || job.JobState == JobState.Expired
          || (job.JobTitle && job.JobTitle.length)) {
          ...
          }
    
    • 嵌套判断尽早返回,嵌套不要超过三层
    if (!user.userName) return NO;
    if (!user.password) return NO;
    if (!user.email) return NO;
    
    return YES;
    
    • 不要反向判断非值
    // 这个写法不是很好
    if (!isNotMember) {...} else {...} 
    // 这个写法很清晰
    if (isNotMember) {...} else {...}
    
    • 声明一个OC对象使用 变量类型 *变量名,而不是变量类型* 变量名,也不是变量类型*变量名
    //这样是规范的 
    NSString *name 
    //以下都是不规范的 
    NSString * name 
    NSString* name 
    NSString*name
    
    • 可以使用字面量语法初始化的类,用可读性高的字面量进行初始化
    • 声明枚举,用NS_ENUM宏进行声明
    typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
      RWTLeftMenuTopItemTypeMain,
      RWTLeftMenuTopItemTypeShows,
      RWTLeftMenuTopItemTypeSchedule
    };
    
    • 一元运算符与变量之间没有空格
    !bValue
    ~iValue
    ++iCount
    *strSource
    &fSum
    
    • 二元运算符与变量之间必须有空格
    fWidth = 5 + 5;
    fLength = fWidth * 2;
    fHeight = fWidth + fLength;
    for(int i = 0; i < 10; i++)
    

    5.图片命名规范

    • 工程中的图片一律放入Assets.xcassets文件夹中进行管理
    • 工程中的文件夹以模块为界进行创建,如果一个模块中还有子模块,那么可以再在其中对应文件夹以区分子模块。
    • 工程中的图片命名规则:能够描述清楚图片的用途和用在什么地方 例:
    • Home(工程的模块文件夹)
      • home_city
      • home_scan
      • QXC(子模块文件夹)
        • qxc_shop_basket_gray
        • qxc_shop_basket

    6.工程前缀

    • 例如(我们以牛股王工程来举例):
    • API: Ngw_API
    • Model:MNgw_

    7.Apple的代码规范

    😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄
    以上都是个人的总结和建议,如果有什么错误或者不合适的地方,以及需要补充的地方,请大家多多提出自己宝贵的意见和建议。
    😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄

    相关文章

      网友评论

          本文标题:iOS开发代码规范

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