OC:开发语言规范

一、语言

优先使用美式英语。

推荐:

UIColor *myColor = [UIColor whiteColor];

不推荐

UIColor *myColour = [UIColor whiteColor];

二、代码组织

在功能分组和协议/委托实现中,使用 #pragma mark - 这个通用结构对方法进行分类。

#pragma mark - Lifecycle

- (instancetype)init {}
- (void)dealloc {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}

#pragma mark - Custom Accessors

- (void)setCustomProperty:(id)value {}
- (id)customProperty {}

#pragma mark - IBActions

- (IBAction)submitData:(id)sender {}

#pragma mark - Public

- (void)publicMethod {}

#pragma mark - Private

- (void)privateMethod {}

#pragma mark - Protocol conformance
#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate

#pragma mark - NSCopying

- (id)copyWithZone:(NSZone *)zone {}

#pragma mark - NSObject

- (NSString *)description {}

三、空格

  • 使用2个空格缩进(这样可以节省打印空间,减少换行)。不要用制表符缩进。请确保在Xcode中设置这个首选项。
  • 方法大括号和其他大括号(if/else/switch/while等)总是在同一行打开,但在另一行关闭。

推荐:

if (user.isHappy) {
  //Do something
} else {
  //Do something else
}

不推荐:

if (user.isHappy)
{
    //Do something
}
else {
    //Do something else
}
  • 方法之间应该有一个空行,以帮助可视化的清晰度和组织。方法中的空格应该分隔功能,但通常应该有新方法。
  • 优先使用auto-synthesis。但是如果必要的话,@synthesize和@dynamic应该分别在实现的新行中声明。
  • 应该避免经常使用冒号对齐的方法调用。在某些情况下,方法签名可能具有>= 3冒号,而对冒号进行对齐可以提高代码的可读性。但不要对包含块的方法使用冒号对齐,因为Xcode的缩进使其难以辨认。

推荐:

// blocks are easily readable
[UIView animateWithDuration:1.0 animations:^{
  // something
} completion:^(BOOL finished) {
  // something
}];

不推荐:

[UIView animateWithDuration:1.0
                 animations:^{
                     // something
                 }
                 completion:^(BOOL finished) {
                     // something
                 }];

四、命名

应该尽可能遵循Apple的命名约定,特别是那些与内存管理规则相关的。长的,描述性的方法和变量名是比较不错的。

推荐

UIButton *settingsButton;

不推荐

UIButton *setBut;

类名和常量应该始终使用三个字母的前缀,但于核心数据实体名称可以省略。常量应为驼峰大小写,所有单词都应大写,并以相关类名作为前缀。

推荐:

static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3;

不推荐:

static NSTimeInterval const fadetime = 1.7;

属性名使用驼峰大小写,前导字为小写。如无特殊需要,使用属性的自动合成而不是手动的@synthesize语句。

推荐:

@property (nonatomic, strong) NSString *descriptiveVariableName;

不推荐:

id varnm;

五、下划线

在使用属性时,应该始终使用self访问和修改实例变量。这里有一个例外:在初始值设定的内部,应该直接使用下划线实例变量(例如_variableName)来避免getter /setter的副作用。

局部变量不应包含下划线。

六、方法

在方法签名中,方法类型(-/+符号)后面应该有一个空格。方法段之间应该有一个空格(匹配苹果的风格)。在参数之前,要包含一个关键字,并在描述参数的参数之前使用该词进行描述。

and 是保留词,不能应用于多个参数的方法中。

推荐:

- (void)setExampleText:(NSString *)text image:(UIImage *)image;
- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
- (id)viewWithTag:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;

不推荐:

-(void)setT:(NSString *)text i:(UIImage *)image;
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
- (id)taggedView:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
- (instancetype)initWith:(int)width and:(int)height; 

七、变量

变量的命名应尽可能具有描述性。除for()循环外,应避免使用单字母变量名。私有属性应该尽可能地代替实例变量。虽然使用实例变量是一种有效的方法,但是通过使用属性,我们的代码将更加一致。

推荐:

@interface RWTTutorial : NSObject

@property (strong, nonatomic) NSString *tutorialName;

@end

不推荐:

@interface RWTTutorial : NSObject {
  NSString *tutorialName;
}

八、Property Attributes

属性的顺序应该是存储,然后是原子性,这与从Interface Builder连接UI元素时自动生成的代码一致。

推荐:

@property (weak, nonatomic) IBOutlet UIView *containerView;
@property (strong, nonatomic) NSString *tutorialName;

不推荐:

@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic) NSString *tutorialName;

具有可变对应项的属性(例如NSString)应首选copy而不是strong。

推荐:

@property (copy, nonatomic) NSString *tutorialName;

不推荐:

@property (strong, nonatomic) NSString *tutorialName;

九、点符号语法

点语法纯粹是访问器方法调用的方便包装器。使用点语法时,仍然可以使用getter和setter方法访问或更改属性。在这里阅读更多

点表示法应该始终用于访问和更改属性,因为它使代码更简洁。在所有其他情况下,最好使用括号表示法。

推荐:

NSInteger arrayCount = [self.array count];
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;

不推荐:

NSInteger arrayCount = self.array.count;
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;

十、字面量

每当创建这些对象的不可变实例时,都应该使用 NSStringNSDictionaryNSArrayNSNumber 的字面量。

推荐:

NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;

不推荐:

NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingStreetNumber = [NSNumber numberWithInteger:10018];

十一、常量

常量应该声明为静态常量,而不是#define,除非显式地用作宏。

推荐:

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

static CGFloat const RWTImageThumbnailHeight = 50.0;

不推荐:

#define CompanyName @"RayWenderlich.com"

#define thumbnailHeight 2

十二、枚举类型

使用枚举时,建议使用新的固定基础类型规范,因为它具有更强的类型检查和代码完成能力。SDK现在包含一个宏来促进和鼓励使用固定的底层类型:NS_ENUM

推荐:

typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
  RWTLeftMenuTopItemMain,
  RWTLeftMenuTopItemShows,
  RWTLeftMenuTopItemSchedule
};

不推荐:

enum GlobalConstants {
  kMaxPinSize = 5,
  kMaxPinCount = 500,
};

十三、case语句

case语句不需要大括号,当case下包含多行时,应添加大括号。

switch (condition) {
  case 1:
    // ...
    break;
  case 2: {
    // ...
    // Multi-line example using braces
    break;
  }
  default: 
    // ...
    break;
}

有时同一个代码可以用于多个情况,应该使用一个fall-through。fall-through是删除一个case的 break 语句,从而允许执行流传递到下一个case值。为了代码的清晰性,应该对fall-through进行注释。

switch (condition) {
  case 1:
    // ** fall-through! **
  case 2:
    // code executed for values 1 and 2
    break;
  default: 
    // ...
    break;
}

当使用枚举类型时,default 不是必须的。

RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;

switch (menuType) {
  case RWTLeftMenuTopItemMain:
    // ...
    break;
  case RWTLeftMenuTopItemShows:
    // ...
    break;
  case RWTLeftMenuTopItemSchedule:
    // ...
    break;
}

十四、私有属性

私有属性应该在类的实现文件中的类扩展(匿名类别)中声明。除非扩展另一个类,否则不应使用命名类别(如RWTPrivate或private)。可以使用+Private.h文件命名约定共享/公开匿名类别以进行测试。

@interface RWTDetailViewController ()

@property (strong, nonatomic) GADBannerView *googleAdView;
@property (strong, nonatomic) ADBannerView *iAdView;
@property (strong, nonatomic) UIWebView *adXWebView;

@end

十五、布尔值

OC使用 YESNO,因此 falsetrue 只适用于CoreFoundation、C 或 C++代码。由于 nil 解析为 NO,所以没有必要在条件中比较它。不要直接将某个值与 YES 进行比较,因为 YES 被定义为1,而BOOL 最多可为8位。

这使得文件之间的一致性和视觉清晰度更高。

推荐:

if (someObject) {}
if (![anotherObject boolValue]) {}

不推荐:

if (someObject == nil) {}
if ([anotherObject boolValue] == NO) {}
if (isAwesome == YES) {} // 不要这么做
if (isAwesome == true) {} // 不要这么做

如果BOOL属性的名称用形容词表示,则该属性可以省略“is”前缀,但指定get访问器的常规名称,例如:

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

十六、条件句

条件体应该始终使用大括号,即使条件体可以不带大括号(例如,只有一行)来编写,以防止出现错误。

推荐:

if (!error) {
  return success;
}

不推荐:

if (!error)
  return success;

if (!error) return success;

十七、init方法

Init方法应该遵循苹果生成的代码模板提供的约定。还应使用 instancetype 的返回类型,而不是 id

- (instancetype)init {
  if (self = [super init]) {
    // ...
  }
  return self;
}

十八、类构造方法

在使用类构造函数方法的地方,这些方法应始终返回 instancetype 类型,而从不返回 id。这可以确保编译器正确推断结果类型。

@interface Airplane
+ (instancetype)airplaneWithType:(RWTAirplaneType)type;
@end

关于instancetype的更多信息,可以参考这里。

十九、CGRect方法

访问CGRect的x、y、width或height时,建议始终使用CGGeometry函数,而不是直接访问struct成员。来自苹果公司的CGGeometry参考:

All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.

推荐:

CGRect frame = self.view.frame;

CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
CGRect frame = CGRectMake(0.0, 0.0, width, height);

不推荐:

CGRect frame = self.view.frame;

CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };

二十、黄金路线

使用条件句编码时,代码的左边距应该是“黄金”或“幸福”路径。也就是说,不要嵌套if语句,多个return语句是可以的。

推荐:

- (void)someMethod {
  if (![someOther boolValue]) {
    return;
  }

  //Do something important
}

不推荐:

- (void)someMethod {
  if ([someOther boolValue]) {
    //Do something important
  }
}

二十一、错误控制

当方法通过引用返回错误参数时,根据返回值,而不是错误变量。苹果的一些api在成功的情况下会将垃圾值写入error参数(如果非NULL),因此根据错误会导致误报。

推荐:

NSError *error;
if (![self trySomethingWithError:&error]) {
  // Handle Error
}

不推荐:

NSError *error;
[self trySomethingWithError:&error];
if (error) {
  // Handle Error
}

二十二、单例

单例对象应该使用线程安全的模式来创建它们的共享实例。

+ (instancetype)sharedInstance {
  static id sharedInstance = nil;

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

  return sharedInstance;
}

参考:

https://github.com/raywenderlich/objective-c-style-guide

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