OC:開發(fā)語(yǔ)言規(guī)范

一、語(yǔ)言

優(yōu)先使用美式英語(yǔ)。

推薦:

UIColor *myColor = [UIColor whiteColor];

不推薦

UIColor *myColour = [UIColor whiteColor];

二、代碼組織

在功能分組和協(xié)議/委托實(shí)現(xiàn)中,使用 #pragma mark - 這個(gè)通用結(jié)構(gòu)對(duì)方法進(jìn)行分類。

#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個(gè)空格縮進(jìn)(這樣可以節(jié)省打印空間,減少換行)。不要用制表符縮進(jìn)。請(qǐng)確保在Xcode中設(shè)置這個(gè)首選項(xiàng)。
  • 方法大括號(hào)和其他大括號(hào)(if/else/switch/while等)總是在同一行打開,但在另一行關(guān)閉。

推薦:

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

不推薦:

if (user.isHappy)
{
    //Do something
}
else {
    //Do something else
}
  • 方法之間應(yīng)該有一個(gè)空行,以幫助可視化的清晰度和組織。方法中的空格應(yīng)該分隔功能,但通常應(yīng)該有新方法。
  • 優(yōu)先使用auto-synthesis。但是如果必要的話,@synthesize和@dynamic應(yīng)該分別在實(shí)現(xiàn)的新行中聲明。
  • 應(yīng)該避免經(jīng)常使用冒號(hào)對(duì)齊的方法調(diào)用。在某些情況下,方法簽名可能具有>= 3冒號(hào),而對(duì)冒號(hào)進(jìn)行對(duì)齊可以提高代碼的可讀性。但不要對(duì)包含塊的方法使用冒號(hào)對(duì)齊,因?yàn)閄code的縮進(jìn)使其難以辨認(rèn)。

推薦:

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

不推薦:

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

四、命名

應(yīng)該盡可能遵循Apple的命名約定,特別是那些與內(nèi)存管理規(guī)則相關(guān)的。長(zhǎng)的,描述性的方法和變量名是比較不錯(cuò)的。

推薦

UIButton *settingsButton;

不推薦

UIButton *setBut;

類名和常量應(yīng)該始終使用三個(gè)字母的前綴,但于核心數(shù)據(jù)實(shí)體名稱可以省略。常量應(yīng)為駝峰大小寫,所有單詞都應(yīng)大寫,并以相關(guān)類名作為前綴。

推薦:

static NSTimeInterval const RWTTutorialViewControllerNavigationFadeAnimationDuration = 0.3;

不推薦:

static NSTimeInterval const fadetime = 1.7;

屬性名使用駝峰大小寫,前導(dǎo)字為小寫。如無(wú)特殊需要,使用屬性的自動(dòng)合成而不是手動(dòng)的@synthesize語(yǔ)句。

推薦:

@property (nonatomic, strong) NSString *descriptiveVariableName;

不推薦:

id varnm;

五、下劃線

在使用屬性時(shí),應(yīng)該始終使用self訪問(wèn)和修改實(shí)例變量。這里有一個(gè)例外:在初始值設(shè)定的內(nèi)部,應(yīng)該直接使用下劃線實(shí)例變量(例如_variableName)來(lái)避免getter /setter的副作用。

局部變量不應(yīng)包含下劃線。

六、方法

在方法簽名中,方法類型(-/+符號(hào))后面應(yīng)該有一個(gè)空格。方法段之間應(yīng)該有一個(gè)空格(匹配蘋果的風(fēng)格)。在參數(shù)之前,要包含一個(gè)關(guān)鍵字,并在描述參數(shù)的參數(shù)之前使用該詞進(jìn)行描述。

and 是保留詞,不能應(yīng)用于多個(gè)參數(shù)的方法中。

推薦:

- (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; 

七、變量

變量的命名應(yīng)盡可能具有描述性。除for()循環(huán)外,應(yīng)避免使用單字母變量名。私有屬性應(yīng)該盡可能地代替實(shí)例變量。雖然使用實(shí)例變量是一種有效的方法,但是通過(guò)使用屬性,我們的代碼將更加一致。

推薦:

@interface RWTTutorial : NSObject

@property (strong, nonatomic) NSString *tutorialName;

@end

不推薦:

@interface RWTTutorial : NSObject {
  NSString *tutorialName;
}

八、Property Attributes

屬性的順序應(yīng)該是存儲(chǔ),然后是原子性,這與從Interface Builder連接UI元素時(shí)自動(dòng)生成的代碼一致。

推薦:

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

不推薦:

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

具有可變對(duì)應(yīng)項(xiàng)的屬性(例如NSString)應(yīng)首選copy而不是strong。

推薦:

@property (copy, nonatomic) NSString *tutorialName;

不推薦:

@property (strong, nonatomic) NSString *tutorialName;

九、點(diǎn)符號(hào)語(yǔ)法

點(diǎn)語(yǔ)法純粹是訪問(wèn)器方法調(diào)用的方便包裝器。使用點(diǎn)語(yǔ)法時(shí),仍然可以使用getter和setter方法訪問(wèn)或更改屬性。在這里閱讀更多

點(diǎn)表示法應(yīng)該始終用于訪問(wèn)和更改屬性,因?yàn)樗勾a更簡(jiǎn)潔。在所有其他情況下,最好使用括號(hào)表示法。

推薦:

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

不推薦:

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

十、字面量

每當(dāng)創(chuàng)建這些對(duì)象的不可變實(shí)例時(shí),都應(yīng)該使用 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];

十一、常量

常量應(yīng)該聲明為靜態(tài)常量,而不是#define,除非顯式地用作宏。

推薦:

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

static CGFloat const RWTImageThumbnailHeight = 50.0;

不推薦:

#define CompanyName @"RayWenderlich.com"

#define thumbnailHeight 2

十二、枚舉類型

使用枚舉時(shí),建議使用新的固定基礎(chǔ)類型規(guī)范,因?yàn)樗哂懈鼜?qiáng)的類型檢查和代碼完成能力。SDK現(xiàn)在包含一個(gè)宏來(lái)促進(jìn)和鼓勵(lì)使用固定的底層類型:NS_ENUM

推薦:

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

不推薦:

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

十三、case語(yǔ)句

case語(yǔ)句不需要大括號(hào),當(dāng)case下包含多行時(shí),應(yīng)添加大括號(hào)。

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

有時(shí)同一個(gè)代碼可以用于多個(gè)情況,應(yīng)該使用一個(gè)fall-through。fall-through是刪除一個(gè)case的 break 語(yǔ)句,從而允許執(zhí)行流傳遞到下一個(gè)case值。為了代碼的清晰性,應(yīng)該對(duì)fall-through進(jìn)行注釋。

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

當(dāng)使用枚舉類型時(shí),default 不是必須的。

RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;

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

十四、私有屬性

私有屬性應(yīng)該在類的實(shí)現(xiàn)文件中的類擴(kuò)展(匿名類別)中聲明。除非擴(kuò)展另一個(gè)類,否則不應(yīng)使用命名類別(如RWTPrivate或private)。可以使用+Private.h文件命名約定共享/公開匿名類別以進(jìn)行測(cè)試。

@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,所以沒(méi)有必要在條件中比較它。不要直接將某個(gè)值與 YES 進(jìn)行比較,因?yàn)?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訪問(wèn)器的常規(guī)名稱,例如:

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

十六、條件句

條件體應(yīng)該始終使用大括號(hào),即使條件體可以不帶大括號(hào)(例如,只有一行)來(lái)編寫,以防止出現(xiàn)錯(cuò)誤。

推薦:

if (!error) {
  return success;
}

不推薦:

if (!error)
  return success;

if (!error) return success;

十七、init方法

Init方法應(yīng)該遵循蘋果生成的代碼模板提供的約定。還應(yīng)使用 instancetype 的返回類型,而不是 id

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

十八、類構(gòu)造方法

在使用類構(gòu)造函數(shù)方法的地方,這些方法應(yīng)始終返回 instancetype 類型,而從不返回 id。這可以確保編譯器正確推斷結(jié)果類型。

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

關(guān)于instancetype的更多信息,可以參考這里。

十九、CGRect方法

訪問(wèn)CGRect的x、y、width或height時(shí),建議始終使用CGGeometry函數(shù),而不是直接訪問(wèn)struct成員。來(lái)自蘋果公司的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 };

二十、黃金路線

使用條件句編碼時(shí),代碼的左邊距應(yīng)該是“黃金”或“幸福”路徑。也就是說(shuō),不要嵌套if語(yǔ)句,多個(gè)return語(yǔ)句是可以的。

推薦:

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

  //Do something important
}

不推薦:

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

二十一、錯(cuò)誤控制

當(dāng)方法通過(guò)引用返回錯(cuò)誤參數(shù)時(shí),根據(jù)返回值,而不是錯(cuò)誤變量。蘋果的一些api在成功的情況下會(huì)將垃圾值寫入error參數(shù)(如果非NULL),因此根據(jù)錯(cuò)誤會(huì)導(dǎo)致誤報(bào)。

推薦:

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

不推薦:

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

二十二、單例

單例對(duì)象應(yīng)該使用線程安全的模式來(lái)創(chuàng)建它們的共享實(shí)例。

+ (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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。