[关闭]
@FoxBabe 2016-01-03T11:55:10.000000Z 字数 7909 阅读 1597

浙江我财 Objective-C 编码规范


介绍


关于这个编程语言的所有规范,如果这里没有写到,那就在苹果的文档里:

目录


基本原则


点语法


应该 始终 使用点语法来访问或者修改属性,访问其他实例时首选括号。

推荐:

  1. view.backgroundColor = [UIColor orangeColor];
  2. [UIApplication sharedApplication].delegate;

反对:

  1. [view setBackgroundColor:[UIColor orangeColor]];
  2. UIApplication.sharedApplication.delegate;

间距


推荐:

  1. if (user.isHappy) {
  2. // Do something
  3. } else {
  4. // Do something else
  5. }

反对:

  1. if (user.isHappy)
  2. {
  3. // Do something
  4. }else
  5. {
  6. // Do something else
  7. }

条件判断


条件判断主体部分应该始终使用大括号括住来防止出错,即使它可以不用大括号(例如它只需要一行)。这些错误包括添加第二行(代码)并希望它是 if 语句的一部分时。还有另外一种更危险的,当 if 语句里面的一行被注释掉,下一行就会在不经意间成为了这个 if 语句的一部分。此外,这种风格也更符合所有其他的条件判断,因此也更容易检查。

推荐:

  1. if (!error) {
  2. return success;
  3. }

反对:

  1. if (!error)
  2. return success;

反对:

  1. if (!error) return success;

三目运算符

三目运算符,? ,只有当它可以增加代码清晰度或整洁时才使用。单一的条件都应该优先考虑使用。多条件时通常使用 if 语句会更易懂,或者重构为实例变量。

推荐:

  1. result = a > b ? x : y;

反对:

  1. result = a > b ? x = c > d ? c : d : y;

错误处理


当引用一个返回错误参数(error parameter)的方法时,应该针对返回值,而非错误变量。

推荐:

  1. NSError *error;
  2. if (![self trySomethingWithError:&error]) {
  3. // 处理错误
  4. }

反对:

  1. NSError *error;
  2. [self trySomethingWithError:&error];
  3. if (error) {
  4. // 处理错误
  5. }

一些苹果的 API 在成功的情况下会写一些垃圾值给错误参数(如果非空),所以针对错误变量可能会造成虚假结果(以及接下来的崩溃)。

方法

在方法签名中,在 -/+ 符号后应该有一个空格。方法片段之间也应该有一个空格。

始终:

  1. - (void)setExampleText:(NSString *)text image:(UIImage *)image;

反对:

  1. -(void) setExampleText:(NSString *)text image:(UIImage *)image;
  2. -(void)setExampleText:(NSString *)text image:(UIImage *)image;

变量


推荐:

  1. @interface WCSection: NSObject
  2. @property (nonatomic) NSString *headline;
  3. @end

反对:

  1. @interface WCSection : NSObject {
  2. NSString *headline;
  3. }

当涉及到在 ARC 中被引入变量限定符时,
限定符 (__strong, __weak, __unsafe_unretained, __autoreleasing) 应该位于星号和变量名之间,如:NSString * __weak text

命名


长的和描述性的方法名和变量名都不错。

推荐:

  1. UIButton *settingsButton;

反对:

  1. UIButton *setBut;
  2. UIButton *setting;
  3. UIButton *set;

推荐:

  1. static const NSTimeInterval WCArticleViewControllerNavigationFadeAnimationDuration = 0.3;

反对:

  1. static const NSTimeInterval fadetime = 1.7;

注释


推荐:

  1. //
  2. // LoginViewController.h
  3. // [ProjectName]
  4. //
  5. // Created by [Author] on 15-7-16.
  6. // Copyright (c) 2015年 浙江我财网络科技有限公司. All rights reserved.

代码标记


  1. // TODO: 处理异常情况 (标记待处理的事情)
  2. // FIXME: 此处需要清除缓存(标记说明此处还需要修复的内容)
  3. // !!!: 此处逻辑不严谨,待完善 (特别注意)
  4. // ???: 这块的实现上还存在难度,待研究跟进 (疑问或有待研究)
  5. #warning 此处在特定情况下会出现异常,提交版本前一定要处理 (主动设置警告)

前四种为备注说明,并且在预览方法时会清晰显示出来,后面warnning,是在编译程序后都会直接作为一个警告出现在编译结果中。
在实际开发中,如果开发到中途,要需要处理的,务必加上对应的标志,防止再次来编辑时遗漏。另外,在提交版本前,一定要对这些标志进行一次检查,warnning能很明显的发现,其他四种可以采用插件Xcode插件XToDo来查找。

init


  1. - (instancetype)init {
  2. self = [super init]; // 或者调用指定的初始化方法
  3. if (self) {
  4. // Custom initialization
  5. }
  6. return self;
  7. }

字面量

每当创建 NSStringNSDictionaryNSArray,和 NSNumber 类的不可变实例时,都应该使用字面量。要注意 nil 值不能传给 NSArrayNSDictionary 字面量,这样做会导致崩溃。

推荐:

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

反对:

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

CGRect 函数

当访问一个 CGRectxywidthheight 时,应该使用CGGeometry 函数代替直接访问结构体成员。苹果的 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.

推荐:

  1. CGRect frame = self.view.frame;
  2. CGFloat x = CGRectGetMinX(frame);
  3. CGFloat y = CGRectGetMinY(frame);
  4. CGFloat width = CGRectGetWidth(frame);
  5. CGFloat height = CGRectGetHeight(frame);

反对:

  1. CGRect frame = self.view.frame;
  2. CGFloat x = frame.origin.x;
  3. CGFloat y = frame.origin.y;
  4. CGFloat width = frame.size.width;
  5. CGFloat height = frame.size.height;

常量


常量首选内联字符串字面量或数字,因为常量可以轻易重用并且可以快速改变而不需要查找和替换。常量应该声明为 static 常量而不是 #define ,除非非常明确地要当做宏来使用。

推荐:

  1. static NSString * const WCAboutViewControllerCompanyName = @"ZJWoCai Company";
  2. static const CGFloat WCImageThumbnailHeight = 50.0;

反对:

  1. #define CompanyName @"ZJWoCai Company"
  2. #define thumbnailHeight 2

枚举类型


当使用 enum 时,建议使用新的基础类型规范,因为它具有更强的类型检查和代码补全功能。现在 SDK 包含了一个宏来鼓励使用使用新的基础类型 - NS_ENUM()

推荐:

  1. typedef NS_ENUM(NSInteger, WCAdRequestState) {
  2. WCAdRequestStateInactive,
  3. WCAdRequestStateLoading
  4. };

位掩码


当用到位掩码时,使用 NS_OPTIONS 宏。

举例:

  1. typedef NS_OPTIONS(NSUInteger, WCAdCategory) {
  2. WCAdCategoryAutos = 1 << 0,
  3. WCAdCategoryJobs = 1 << 1,
  4. WCAdCategoryRealState = 1 << 2,
  5. WCAdCategoryTechnology = 1 << 3
  6. };

私有属性


私有属性应该声明在类实现文件的延展(匿名的类目)中。有名字的类目(例如 WCPrivateprivate)永远都不应该使用,除非要扩展其他类。

推荐:

  1. @interface WCAdvertisement ()
  2. @property (nonatomic, strong) GADBannerView *googleAdView;
  3. @property (nonatomic, strong) ADBannerView *iAdView;
  4. @property (nonatomic, strong) UIWebView *adXWebView;
  5. @end

通知


推荐:

  1. NSApplicationDidBecomeActiveNotification
  2. NSWindowDidMiniaturizeNotification
  3. NSTextViewDidChangeSelectionNotification

推荐:

  1. //.h文件中声明
  2. extern NSString * const UserProfileImageDidLoadNotification;
  3. //.m中实现
  4. NSString * const UserProfileImageDidLoadNotification = @"com.alamofire.user.profile-image.loaded";

反对:

  1. #Define UserProfileImageDidLoadNotification = “com.alamofire.user.profile-image.loaded”;

block


推荐

  1. typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType);
  2. typedef void(^SDWebImageDownloaderProgressBlock)(NSUInteger receivedSize, long long expectedSize);

block类型命名规则约定:[类名]+[状态](可选 + [条件描述,如withxxx])+ Block。

图片命名


推荐:

  1. * `RefreshBarButtonItem` / `RefreshBarButtonItem@2x` `RefreshBarButtonItemSelected` / `RefreshBarButtonItemSelected@2x`
  2. * `ArticleNavigationBarWhite` / `ArticleNavigationBarWhite@2x` `ArticleNavigationBarBlackSelected` / `ArticleNavigationBarBlackSelected@2x`.

图片目录中被用于类似目的的图片应归入各自的组中。

布尔


因为 nil 解析为 NO,所以没有必要在条件中与它进行比较。永远不要直接和 YES 进行比较,因为 YES 被定义为 1,而 BOOL 可以多达 8 位。

这使得整个文件有更多的一致性和更大的视觉清晰度。

推荐:

  1. if (!someObject) {
  2. }

反对:

  1. if (someObject == nil) {
  2. }

对于 BOOL 来说, 这有两种用法:

推荐:

  1. if (isAwesome)
  2. if (![someObject boolValue])

反对:

  1. if ([someObject boolValue] == NO)
  2. if (isAwesome == YES) // 永远别这么做

如果一个 BOOL 属性名称是一个形容词,属性可以省略 “is” 前缀,但为 get 访问器指定一个惯用的名字,例如:

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

内容和例子来自 Cocoa 命名指南

单例


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

推荐:

  1. + (instancetype)sharedInstance {
  2. static id sharedInstance = nil;
  3. static dispatch_once_t onceToken;
  4. dispatch_once(&onceToken, ^{
  5. sharedInstance = [[self alloc] init];
  6. });
  7. return sharedInstance;
  8. }

这将会预防有时可能产生的许多崩溃

Xcode 工程


参考


本编码规范主要参考下面几则规范,有兴趣看看对应的风格指南:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注