通用的約定
盡可能遵守 Apple 的命名約定,
推薦使用長的、描述性的方法和變量名。
通用約定:
UIButton *shareButton;
不推薦:
UIButton *shareBut;
//常量應該以駝峰法命名,并以相關(guān)類名作為前綴。
static const NSTimeInterval ZOCSignInViewControllerFadeOutAnimationDu
ration = 0.4;
推薦使用常量來代替字符串字面值和數(shù)字,
這樣能方便復用,而且還可以快速的修改,替換。
常量應該用static來聲明為靜態(tài)常量,而不要用#define,除非它明確的作為一個宏來使用。
static AppName @"最適碼"
不推薦:
#define AppName @"最適碼"
常量應該以如下方式暴露給外部:
extern NSString *const AppName;
并在實現(xiàn)文件中為它賦值。
方法
方法名與方法類型 (-/+ 符號)之間應該以空格間隔。
方法段之間也應該以空格間隔。
- (id)viewWithTag:(NSInteger)tag;
字面值
使用字面值來創(chuàng)建不可變的 NSString, NSDictionary, NSArray,
和 NSNumber 對象。
注意不要將 nil 傳進 NSArray 和 NSDictionary 里,因為這樣會導致崩潰。
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
//不要這樣
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
類
類名應該以三個大寫字母作為前綴(雙字母前綴為 Apple 的類預留)。
盡管這個規(guī)范看起來有些古怪,但是這樣做可以減少 Objective-c 沒有命名空間所帶來的問題。
Initializer 和 dealloc
推薦的代碼組織方式是將 dealloc 方法放在實現(xiàn)文件的最前面
(直接在 @synthesize 以及 @dynamic 之后),init 應該跟在 dealloc 方法后面。
如果有多個初始化方法, 指定初始化方法 (designated initializer) 應該放在最前面,
間接初始化方法 (secondary initializer) 跟在后面,
這樣更有邏輯性。如今有了 ARC,dealloc 方法幾乎不需要實現(xiàn),
不過把 init 和 dealloc 放在一起可以從視覺上強調(diào)它們是一對的。
通常,在 init 方法中做的事情需要在 dealloc 方法中撤銷。
init 方法應該是這樣的結(jié)構(gòu):
- (instancetype)init
{
self = [super init]; // call the designated initializer
if (self) {
// Custom initialization
}
return self;
}
為什么設置 self 為 [super init] 的返回值,以及中間發(fā)生了什么呢?這是一個十分有趣的話題。
我們退一步講:我們常常寫 [[NSObject alloc] init] 這樣的代碼,從而淡化了 alloc 和 init 的區(qū)別。Objective-C 的這個特性叫做 兩步創(chuàng)建 。
這意味著申請分配內(nèi)存和初始化被分離成兩步,alloc 和 init。
alloc 負責創(chuàng)建對象,這個過程包括分配足夠的內(nèi)存來保存對象,
寫入 isa 指針,初始化引用計數(shù),以及重置所有實例變量。
init 負責初始化對象,這意味著使對象處于可用狀態(tài)。
這通常意味著為對象的實例變量賦予合理有用的值。
alloc 方法將返回一個有效的未初始化的對象實例。
每一個對這個實例發(fā)送的消息會被轉(zhuǎn)換成一次 objc_msgSend() 函數(shù)的調(diào)用,
形參 self 的實參是 alloc 返回的指針;這樣 self 在所有方法的作用域內(nèi)都能夠被訪問。
按照慣例,為了完成兩步創(chuàng)建,新創(chuàng)建的實例第一個被調(diào)用的方法將是 init 方法。注意,NSObject 在實現(xiàn) init 時,只是簡單的返回了 self。
關(guān)于 init 的約定還有一個重要部分:這個方法可以(并且應該)通過返回 nil 來告訴調(diào)用者,初始化失敗了;初始化可能會因為各種原因失敗,比如一個輸入的格式錯誤了,或者另一個需要的對象初始化失敗了。 這樣我們就能理解為什么總是需要調(diào)用 self = [super init]。如果你的父類說初始化自己的時候失敗了,那么你必須假定你正處于一個不穩(wěn)定的狀態(tài),因此在你的實現(xiàn)里不要繼續(xù)你自己的初始化并且也返回 nil。如果不這樣做,你可能會操作一個不可用的對象,它的行為是不可預測的,最終可能會導致你的程序崩潰。
init 方法在被調(diào)用的時候可以通過重新給 self 重新賦值來返回另一個實例,而非調(diào)用的那個實例。例如類簇,還有一些 Cocoa 類為相等的(不可變的)對象返回同一個實例。
單例
如果可能,請盡量避免使用單例而是依賴注入。 然而,如果一定要用,請使用一個線程安全的模式來創(chuàng)建共享的實例。對于 GCD,用 dispatch_once() 函數(shù)就可以咯
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
使用 dispatch_once(),來控制代碼同步,取代了原來的約定俗成的用法。
dispatch_once()
的優(yōu)點是,它更快,而且語法上更干凈,因為dispatch_once()的意思就是 “把一些東西執(zhí)行一次”,就像我們做的一樣。 這樣同時可以避免 possible and sometimes prolific crashes.
經(jīng)典的單例對象是:一個設備的GPS以及它的加速度傳感器(也稱動作感應器)。
雖然單例對象可以子類化,但這種方式能夠有用的情況非常少見。
必須有證據(jù)表明,給定類的接口趨向于作為單例來使用。
所以,單例通常公開一個sharedInstance的類方法就已經(jīng)足夠了,
沒有任何的可寫屬性需要被暴露出來。
屬性
NSString *text;
不要這樣 :
NSString* text;NSString * text;
點符號
當使用 setter getter 方法的時候盡量使用點符號。應該總是用點符號來訪問以及設置屬性。
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
不要這樣
[view setBackgroundColor:[UIColor orangeColor]];UIApplication.sharedApplication.delegate;
方法
參數(shù)斷言
你的方法可能要求一些參數(shù)來滿足特定的條件(比如不能為nil),
在這種情況下啊最好使用 NSParameterAssert() 來斷言條件是否成立或是拋出一個異常。
私有方法
永遠不要在你的私有方法前加上 _ 前綴。
這個前綴是 Apple 保留的。不要冒重載蘋果的私有方法的險。