阅读 5860

一篇走心的OC代码规范

前言

    适当的代码规范和标准不是消灭代码内容的创造性、优雅性,而是限制过度个性化,以一种普遍认可的统一方式一起做事,进而提高工作效率,降低沟通成本。代码的字里行间流淌着的是软件的血液,质量的提升是尽可能少踩坑、杜绝踩重复的坑,切实提升系统稳定性,码出质量(摘抄自《阿里巴巴Java代码规范》)。

    在整个代码库中一致地使用一种风格可以让工程师专注于其他(更重要的)问题。一致性还可以实现更好的自动化,因为一致的代码允许更有效地开发和操作格式化或重构代码的工具。

    根据约束力度,暂时把规范约定为2个等级,分别是 [必须][建议]

(一)命名规范

1. 通用命名规范

  • Tips:
    所有的命名都应该遵循3个基本原则,即“清晰性”、“一致性”、“不要自我指涉”。
    复制代码
  • [必须] 清晰性:好的命名应该是能自我描述的。

    正例:
    removeObject:、
    [string stringByReplacingOccurrencesOfString:@"1" withString:@"2"]
    反例:
    remove:(要删除什么?)、
    string.replace("1", "2")(是将"1"替换成"2"还是将"2"替换成"1"?是替换首个匹配的字符还是所有匹配的字符?)
    复制代码
  • [必须] 一致性:命名应该和上下文乃至全局保持一致性,相同类型或者具有相同作用的变量的命名方式应该相同或类似。

    正例:
    @property (readonly) NSUInteger count;
    // NSDictionary、NSArray、NSSet这些集合类都是用count来表示集合数量,
    这就是命名的一致性。
    复制代码
  • [必须] 禁止自我指涉:命名不要自我指涉(通知、掩码常量等除外)。

    正例:
    NSString
    反例:
    NSStringObject
    复制代码
  • [必须] 杜绝过度缩写,国际通用缩写名称除外(例如ATM、GPS等)。

    Tips:
    你的代码可能会被任何人阅读,
    而阅读的人来自不同的地方接受不同的教育不同的文化,
    他们不一定会明白你的意思。
    正例:
    destinationSelection、setBackgroundColor
    反例:
    destSel、setBgColor
    复制代码
  • [必须] 严禁自创缩写(例如把button缩写为btn)。

  • [必须] 杜绝无意义的拼音,国际通用名和地名人名除外。

    正例:
    alibaba、hangzhou
    反例:
    DaZhePromotion(打折)
    复制代码
  • [必须] 代码和注释都要避免使用任何语言的种族歧视性词语。

    正例:
    secondary
    反例:
    slave
    复制代码
  • [必须] 所有名称禁止以new、alloc、copy、mutableCopy等关键字开始。

  • [必须] 命名要尽可能清晰并简洁,如果两者不能兼得,则以清晰为主。

    正例:
    insertObject:atIndex:
    反例:
    insert:at:(插入什么?at代表什么?)
    复制代码
  • [必须] 类名、协议名、常量名、枚举名等全局名称需要添加前缀,前缀需要大于2个字符且全部大写。

    Tips: 系统保留任意两个字符作为前缀的使用权,
    包括但不限于NS、UI、CG、CF、CA、WK、MK、CI、NC,
    前缀若等于2个字符可以考虑添加_。
    正例:
    ZT_LoginViewController
    反例:
    ZTLoginViewController
    复制代码
  • [必须] 类名、协议名、常量名、枚举名等全局命名需遵循首字母大写的驼峰命名方式(首个单词是HTTP这种特殊词除外)。

    正例:
    WXYZLoginViewController
    反例:
    WXYZloginViewController
    复制代码
  • [必须] 函数名也应该遵循首字母大写的驼峰命名方式

    正例:
    static void AddTableEntry(NSString *tableEntry);
    static BOOL DeleteFile(const char *filename);
    复制代码
  • [必须] 非静态函数或某个类的函数名称前应添加前缀,如果函数和某个类相关联则应该在函数前面添加类名前缀。

    正例:
    extern NSTimeZone *GTMGetDefaultTimeZone(void);
    extern NSString *GTMGetURLScheme(NSURL *URL);
    复制代码
  • [必须] 方法名、属性名等非全局名称应遵循首字母小写的驼峰命名方式(首个单词是HTTP这种特殊词除外)。

    正例:
    nameLabel
    反例:
    NameLabel
    复制代码
  • [必须] 成员变量需要以_开头。

    正例:
    _nameString;
    反例:
    nameString;
    复制代码
  • [必须] 在给常量或变量命名时,请将表示类型的名词放在词尾,以提高辨识度。

    正例:
    nameLabel、nameString
    反例:
    name(name是字符串还是什么?)
    复制代码
  • [建议] 如果模块、接口、类、方法使用了模式,在命名时尽量体现出具体模式。

    正例:
    OrderFactory、LoginProxy
    复制代码
  • [建议] 建议给临时变量名称添加前缀,以提高辨识度(特殊情况除外,例如for循环里面的i)。

    正例:
    t_label(t在这里表示temp)
    反例:
    label
    复制代码

2. 类命名规范

  • [必须] 类名由"前缀+类的名称+类的类型"3个部分组成,'前缀'必须大于2个字符且全部大写(如果等于2个字符可以在末尾添加_),类名需遵循首字母大写的驼峰式命名方式,'类的名称'要能表达出该类的功能,类的类型必须使用全称,严禁使用缩写(例如使用vc代替viewController等)。

    正例:
    WXYZ_LoginViewControler
    前缀:WXYZ_,
    类的名称:Login(表示该类跟登录相关),
    类的类型:ViewController(表示该类是一个视图控制器而不是View)。
    复制代码

3. 方法命名规范

  • [必须] 所有方法名称禁止使用_开始。

    Tips: 系统的私有方法会使用_开头,为了避免不小心覆盖系统方法,严禁使用_开头给方法命名。
    复制代码
  • [必须] 私有方法需要增加前缀,前缀需要保持唯一性(例如p_)。

    Tips: 给私有方法加前缀有2个好处: 
    1. 增加辨识度,提高代码可读性。
    2. 避免自己的方法无意间覆盖了系统/框架同名的私有方法。
    复制代码
  • [必须] 如果方法返回接收者的某个属性值,那么请直接使用属性名作为方法名。

    正例:
    - (CGSize)cellSize;
    反例:
    - (CGSize)getCellSize;
    复制代码
  • [必须] 如果方法间接返回一个或多个值,那么请用"getXXX"命名,这种命名只适用于返回多个数据项的情况。

    正例:
    - (void)getCachedResponseForDataTask:(NSURLSessionDataTask *)dataTask 
                       completionHandler:(void (^) (NSCachedURLResponse * __nullable cachedResponse))completionHandler;
    复制代码
  • [必须] 方法的每个参数前都必须添加关键字。

    正例:
    - (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag;
    反例:
    - (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
    复制代码
  • [必须] 如果方法是由通知触发的,那么请添加Notification关键字作为后缀。

    正例:
    - (void)appDidBecomeActiveNotification;
    反例:
    - (void)appDidBecomeActive;
    复制代码
  • [建议] 参数之前的单词尽量能描述参数的意义。

    正例:
    - (id)viewWithTag:(NSInteger)aTag;
    反例:
    - (id)taggedView:(int)aTag;
    复制代码
  • [建议] 请不要使用“and”连接接收者属性,尽管and读起来还算顺口,但随着你创建的方法参数的增加,这将会带来一系列的问题。

    正例:
    - (int)runModalForDirectory:(NSString *)path file:(NSString *)name types:(NSArray *)fileTypes;
    反例:
    - (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;
    复制代码
  • [建议] 如果方法描述了两个独立的动作,则可以使用"and"连接起来。

    正例:
    - (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;
    复制代码

4. Protocol命名规范

  • [必须] Protocol中的方法命名以触发消息的对象名开头,省略类名前缀并首字母小写,如果它没有关联任何类则可以忽略这个规则。

    正例:
    - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
    复制代码
  • [必须] 除非Protocol方法只有一个参数,否则冒号需紧跟在类名后面。

    正例:
    - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
    - (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
    复制代码

5. Category命名规范

  • [必须] 分类名也要和类名一样添加前缀。

    正例:
    UIView (YYAdd)
    反例:
    UIView (Add)
    复制代码
  • [必须] 分类中声明的方法名必须要添加前缀,防止覆盖系统的私有方法。

    正例:
    mp_start
    反例:
    start
    复制代码
  • [建议] 分类中尽量不要声明属性,能挪尽量挪到主类中声明。

    Tips: 尽管从技术上来讲可以在分类中声明属性,但是这么做需要格外小心,
    因为它很容易出现内存上或其他一些问题,而且出现问题很难排查。
    复制代码
  • [建议] 如果一个类比较复杂,那么建议使用分类组织代码(可以参考系统的UIView)。

6. Notification命名规范

  • [必须] Notification的命名风格由"类名前缀" + "通知事件名称" + "Notification"3个部分组成。

    正例:
    UIApplicationDidBecomeActiveNotification
    UIApplication表示该通知属于谁,
    DidBecomeActive表示该通知的作用,
    Notification表示它是一个通知。
    复制代码
  • [建议] 如果一个类声明了delegate属性,通常情况下,这个类的delegate对象应该可以通过实现的delegate方法收到大部分通知消息。

    Tips: 
    例如applicationDidBecomeActive:代理方法和NSApplicationDidBecomeActiveNotification通知
    (注意这里的方法名和通知名遵守了命名规范的基本原则"一致性")。
    复制代码

7. 常量命名规范

  • [必须] 如果常量局限于某"编译单元"之内,通常在前面加小写字母k作为前缀,若常量在全局可见,通常以类名作为前缀,然后采用首字母大写驼峰命名方式。

    正例:
    // 局部可见
    const CGFloat kAnimationDuration = 2.0;
    // 全局可见
    const CGFloat UIActivityIndicatorViewAnimationDuration = 2.0;
    复制代码

8. Exception命名规范

  • [必须] 命令规范和Notification一样,把后缀改为"Exception"即可。

9. 文件命名规范

  • [必须] 文件名全部小写。

  • [必须] 采用_连接单词,不要使用驼峰式命名。

  • [必须] 命名的风格:"模块_属性描述",可根据项目适当增加描述。

    正例:
    public_back@2x.png
    复制代码

(二)工程结构规范

  • [必须] 局部使用的常量、静态变量在@interface之前声明,如果没有@interface就在@implementation前声明。

  • [必须] 同一类型的属性声明放在一块,不同类型的声明用2行空格隔开,属性声明的开始和末尾都要添加一行空格。

    正例:
    @interface MineViewController ()
    
    @property (nonatomic, weak) UIView *headView;
    
    @property (nonatomic, weak) UITableView *tableView;
    
    
    @property (nonatomic, copy) NSArray *dataSourceArray;
    
    @end
    复制代码
  • [必须] 方法归类。

    #pragma mark - LifeCycle(生命周期相关的代码放在最上面)
    
    - (void)dealloc {}
    
    - (void)viewDidLoad {}
    
    - (void)viewWillAppear:(BOOL)animated {}
    
    
    #pragma mark - Public(公开方法)
    
    // code...
    // 上空一行
    // 下空两行
    
    
    #pragma mark - Private(私有方法)
    
    
    #pragma mark - Override(需要覆盖父类的方法)
    
    
    #pragma mark - Notification(通知方法)
    
    
    #pragma mark - Delegate(Delegate需要实现的方法)
    
    
    #pragma mark - Getter/Setter
    复制代码
  • [必须] #pragma mark与下面的代码之间不要有空行。

    正例:
    #pragma mark - Setter
    - (void)setName:(NSString *)name {
        _name = name;
    }
    复制代码
  • [建议] 不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开以提升可读性。

    正例:
    [self createSubviews];
    [self createTableview];
    
    [self netRequest];
    复制代码
  • [建议] 头文件包含顺序应该是相关头文件、操作系统头文件、语言库头文件、最后是其他依赖项的头文件,用空行分隔逻辑上不同的头文件,在每个组中,包含的内容应按首字母顺序排列。

    正例:
    #import "ProjectX/BazViewController.h"
    
    #import <Foundation/Foundation.h>
    
    #include <unistd.h>
    #include <vector>
    
    #include "base/basictypes.h"
    #include "base/integral_types.h"
    #include "util/math/mathutil.h"
    
    #import "ProjectX/BazModel.h"
    #import "Shared/Util/Foo.h"
    复制代码
  • [建议] 一个好的例子

    #import <Foundation/Foundation.h>
    
    @class Bar;
    
    /**
     * A sample class demonstrating good Objective-C style. All interfaces,
     * categories, and protocols (read: all non-trivial top-level declarations
     * in a header) MUST be commented. Comments must also be adjacent to the
     * object they're documenting.
     */
    @interface Foo : NSObject
        
    /** The retained Bar. */
    @property(nonatomic) Bar *bar;
        
    /** The current drawing attributes. */
    @property(nonatomic, copy) NSDictionary<NSString *, NSNumber *> *attributes;
        
    /**
     * Convenience creation method.
     * See -initWithBar: for details about @c bar.
     *
     * @param bar The string for fooing.
     * @return An instance of Foo.
     */
    + (instancetype)fooWithBar:(Bar *)bar;
        
    /**
     * Initializes and returns a Foo object using the provided Bar instance.
     *
     * @param bar A string that represents a thing that does a thing.
     */
    - (instancetype)initWithBar:(Bar *)bar NS_DESIGNATED_INITIALIZER;
        
    /**
     * Does some work with @c blah.
     *
     * @param blah
     * @return YES if the work was completed; NO otherwise.
     */
    - (BOOL)doWorkWithBlah:(NSString *)blah;
    
    @end
    
    
    #import "Shared/Util/Foo.h"
    
    @implementation Foo {
      /** The string used for displaying "hi". */
      NSString *_string;
    }
    
    + (instancetype)fooWithBar:(Bar *)bar {
      return [[self alloc] initWithBar:bar];
    }
    
    - (instancetype)init {
      // Classes with a custom designated initializer should always override
      // the superclass's designated initializer.
      return [self initWithBar:nil];
    }
    
    - (instancetype)initWithBar:(Bar *)bar {
      self = [super init];
      if (self) {
        _bar = [bar copy];
        _string = [[NSString alloc] initWithFormat:@"hi %d", 3];
        _attributes = @{
          @"color" : [UIColor blueColor],
          @"hidden" : @NO
        };
      }
      return self;
    }
    
    - (BOOL)doWorkWithBlah:(NSString *)blah {
      // Work should be done here.
      return NO;
    }
    复制代码

结语

这是一篇关于OC的代码规范,所以大部分的规范和约束都是为OC所编写的;欢迎大家提出更好的建议或改进,我会不断更新完善;最后祝大家码出开心,码出质量。

参考

  1. Cocoa编码规范
  2. 阿里巴巴Java代码规范
  3. Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法
  4. Google的Objective-C风格指南
  5. 网上其他人发布的有关代码规范的文章

下载地址

gitee.com/internetWei…

文章分类
iOS
文章标签