Objective-C编码规范

Xcode

  • 代码行最多应不超过80列
  • 缩进统一使用4空格


    每行80列

    4空格缩进

    代码文件分组应不仅在逻辑目录上体现, 同样在文件体系下分类管理, 即Xcode下的Group应存在对应的文件夹


Class

Class

类的命名应使用大驼峰命名法则, 虽然官方推荐通用的类需要添加前缀,
而只在应用使用的类则不需要使用前缀, 但是为了项目的统一风格, 或者在#import的时候将项目内的类跟第三方, 系统的类区分开, 此处应都添加前缀(前缀应是本项目的2-3个大写字母)

UIApplication
AFNetworking
AFHTTPSessionManager
错误示例
Application
afNetworking
httpSessionManager
Category

Category的命名应使用前缀+扩展类名+功能描述次, 例如要扩展一个基于NSString的解析类, 文件应命名成GTMNSString+Parsing.h, Category的本身命名可以书写成

@interface NSString (GTMStringParsingAdditions)

@end

是的, 文件名跟实际扩展类型可以不同, 如果你用过JSONKit你应该早就发现这一点, 而其中扩展方法应使用前缀, 若是只在项目内使用的方法则直接按普通规则命名如 myCategoryMethodOnAString, 若是作为第三方库被其他项目引用, 则需要在方法前面加前缀命名, 如gtm_myCategoryMethodOnAString

代码分块

无论是protocol还是class都应该使用@pragma mark -来分类方法

#pragma mark - Lifecycle
- (instancetype)init{}
- (void)dealloc{}
- (void)viewDidLoad{}
- (void)viewWillAppear:(BOOL)animated{}
- (void)didReceiveMemoryWarning{}

#pragma mark - IBActions
- (IBAction)submitData:(id)sender{}

#pragma mark - Public
- (void)publicMethod{}

#pragma mark - Private
- (void)privateMethod {}

#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate

同样, 当属性过多时也应该进行分块

#pragma mark - IBOutlet
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UIImage *image;

#pragma mark - Status Property
@property (nonatomic, getter=isEditing) BOOL editing;
@property (nonatomic, getter=isScrolling) BOOL scrolling;
@property (nonatomic, getter=isDragging) BOOL dragging;

#pragma mark - Data
@property (strong, nonatomic) NSDictionary *infoDictionary;
@property (strong, nonatomic) NSArray *dataArray;
@property (strong, nonatomic) NSString *urlString;

关于#import, 很多时候在类里面需要import许多第三方的, 项目的, 系统的类, 虽然书写顺序并不会产生什么影响, 但是我觉得应该需要跟方法分块一样, 对import的类也进行简单分块, 没啥, 顺眼

#import <BlocksKit+UIKit.h>
#import <SVProgressHUD.h>
#import <POP.h>

#import <CoreBluetooth/CoreBluetooth.h>
#import <CoreLocation/CoreLocation.h>
#import <AddressBook/AddressBook.h>
#import <Photos/Photos.h>

#import "GTMIndexViewController.h"
#import "GTMLoginViewController.h"
#import "GTMUserViewController.h"

#import "GTMHTTPCommonUtil"
#import "GTMConfigUtil"
#import "GTMUserModel"

原则是按库的来源分类, 然后如第三, 第四组, 按ViewController跟工具类可以再分开一组, 或者你喜欢UIView的子类可以再来一组, 排列顺序是按由长到短, 而不是字母排序, 没啥, 发现这样更好看

构造方法

构造方法返回值应该是instancetype而不是id

+ (instancetype)sharedManager;
而不是
+ (id)sharedManager;

Methods

书写规范

首先 +/- 后紧跟一个空格与返回值分开,参数类型跟*也要用空格分开,如下, 左边花括号应跟方法声明在同一行, 右边花括号则应独占一行

- (void)setExampleText:(NSString *)text image:(UIImage *)image{
    // doSomething
}
命名规范

方法命名一般规则由动词+名词组成, 应该要书写完整单词, 不使用缩写, 但是and应尽量不用于连接参数, 要达到执行方法就像是在读语句

- (void)invokeWithTarget:(id)target;
- (void)setExampleText:(NSString *)text image:(UIImage *)image;
错误示例:
- (void)invokeWith:(id)target;
- (void)setExampleText:(NSString *)text i:(UIImage *)image;

get/set方法, get方法应该直接使用属性名, 而不要添加get前缀, BOOL返回值状态类型应该使用is前缀命名, 而且其他形容词方法则可以使用can, should等词

- (CGSize)cellSize;
- (BOOL)isEditing;
- (void)setEditing:(BOOL)flag;
- (BOOL)canHide;
- (void)setCanHide:(BOOL)flag;
错误示例:
- (CGSize)getCellSize;
- (NSSize)getEditing;
- (void)changeEditing:(BOOL)flag;
- (BOOL)hide;
- (void)canHide:(BOOL)flag;
方法调用

若是一行能书写完整方法, 当然是最好, 单很多情况下OC因为命名规则, 多参数等原因, 方法调用很容易超过一行80列, 这时候应该选择换行并对齐参数

- (void)doSomethingWith:(GTMFoo *)theFoo
                   rect:(NSRect)theRect
               interval:(float)theInterval {
  ...
}
而不能
[myObject doFooWith:arg1 name:arg2  // some lines with >1 arg
              error:arg3];

[myObject doFooWith:arg1
               name:arg2 error:arg3];

[myObject doFooWith:arg1
          name:arg2  // aligning keywords instead of colons
          error:arg3];

Properties

书写规范

@property后应紧跟空格将属性特性分割开来, 属性特性应按照IBOutlet的特性声明顺序, 即storage、atomicity, 类型与变量名之间应用空格分开, 引用类型的 * 应挨着变量名

@property (copy, nonatomic) NSString *title; 
错误示例:
@property(copy, nonatomic) NSString *title;
@property (nonatomic, copy) NSString *title;
@property(copy, nonatomic) NSString*title;

此处注意, NSString应用copy声明而不是retain或者strong, 因为可能会出现误传NSMutableString导致值会被更新

命名规范

变量命名应遵循小驼峰命名方法, 并书写完整单词, IBOutlet类型变量则应包含完整控件内容

@property (copy, nonatomic) NSString *title;
@property (strong, nonatomic) UIImage *image;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
错误示例
@property (copy, nonatomic) NSString *tle;
@property (strong, nonatomic) UIImage *img;
@property (weak, nonatomic) IBOutlet UILabel *nameLbl;

属性的访问应使用点, 而不是[]

[UIApplication sharedApplication].delegate
self.array.count
而不是
[[UIApplication sharedApplication] delegate]
[self.array count]

若你不确认要获取的值是不是属性, 请用command+鼠标左键点击进去看

属性的使用方式

为保证代码的一致性尽可能使用私有属性, 而不是实例属性

@interface RWTTutorial : NSObject

@property (strong, nonatomic) NSString *tutorialName;

@end
而不是
@interface RWTTutorial : NSObject {
  NSString *tutorialName;
}

私有属性的访问应该统一使用self.xxx来访问, 而不是直接访问_xxx, self.xxx才会调用get方法来获取值, 统一出口才能避免产生不必要的错误

self.tableView.tableFooterView
而不是
_tableView.tableFooterView
常量

类内部使用的常量应使用static进行声明, 而不是#define, 常量的命名遵循大驼峰命名, 需要前缀+具体存在的类+实际含义

static NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";

static CGFloat const RWTImageThumbnailHeight = 50.0;
而不是
#define CompanyName @"RayWenderlich.com"

#define thumbnailHeight 2

全局使用的常量则应该使用extern进行声明, 如notification

extern NSString * const NSApplicationDidBecomeActiveNotification

注意notification声明的常量一定有notification结尾, 还是那句读完名字就能马上知道这变量, 方法是做什么的, 代码自注释

枚举

枚举的声明应使用NS_ENUM语法, 而不enum, 命名规则依旧是大驼峰, 由枚举类型+具体类型单词组成

typedef NS_ENUM(NSInteger, NSTextAlignment) {
    NSTextAlignmentLeft,
    NSTextAlignmentCenter,
    NSTextAlignmentRight,
    NSTextAlignmentJustified,
    NSTextAlignmentNatural
};

其他

BOOL值变量应该只是用YES跟NO. 因为true和false应该只在CoreFoundation,C或C++代码使用.BOOL变量应该直接用于判断, 而不能用于跟YES或者NO比较, 因为BOOL被设定为8位

BOOL status = YES;
if (status){
    // doSomething
}
而不能
BOOL status = YES;
if (status == YES){

}

如果BOOL属性的名字是一个形容词,属性就能忽略"is"前缀,但要指定get访问器的惯用名称。例如:

@property (assign, getter=isEditable) BOOL editable;
单例

单例应该使用标准Objective-C语法创建

+ (instancetype)sharedInstance {
  static id sharedInstance;

  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
      sharedInstance = [[self alloc] init];
  });

  return sharedInstance;
}

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容