1狂巢、了解Objective-C的起源
- Objective-C與C++撑蚌、Java等面向?qū)ο笳Z言類似乒躺,不過很多方面有所差別近速。Objective-C使用了“消息結(jié)構(gòu)”(messaging structure)而非“函數(shù)調(diào)用”(function calling)科展。Objective-C語言由Smalltalk演化而來均牢,Smalltalk是消息型語言的鼻祖。
- 使用消息結(jié)構(gòu)的語言才睹,其運行時所應(yīng)執(zhí)行的代碼由運行環(huán)境來決定徘跪;而使用函數(shù)調(diào)用的語言則由編譯器決定
- Objective-C的重要工作都由“運行期組件”(Runtime Component)而非編譯器來完成。使用Objective-C的面向?qū)ο筇匦运璧娜繑?shù)據(jù)結(jié)構(gòu)及函數(shù)都在運行期組件里面琅攘。運行期組件本質(zhì)上就是一種與開發(fā)者所編代碼相連接的“動態(tài)庫”(dynamic library)垮庐,其代碼能把開發(fā)者編寫的所有程序粘合起來。這樣的話坞琴,只需要更新運行期組件哨查,即可提升應(yīng)用程序性能。
- Objective-C是C的“超集”(superset)剧辐,必須同時掌握C與Objective-C這兩門語言的核心概念寒亥,方能寫出高效的Objective-C代碼。其中最重要的是要理解C語言的內(nèi)存模型(memory model)荧关,這有助于理解Objective-C的內(nèi)存模型及其“引用計數(shù)”(reference counting)機制的工作原理护盈。
2、在類的頭文件中盡量少引入其他文件
- 當必須要在頭文件中引入其他頭文件時在使用#import羞酗。比如你寫的類繼承自某個超類腐宋,則必須引入定義那個超類的頭文件。同理檀轨,如果要生命你寫的類遵從某個協(xié)議胸竞,那么該協(xié)議必須有完整的定義,且不能使用@class参萄。@class只能告訴編譯器有某個協(xié)議卫枝,而此時編譯器卻要知道協(xié)議中定義的方法。
- 每次在頭文件中引入其他文件之前讹挎,都要先問問自己這樣做是否有必要校赤。如果可以用@class聲明取代吆玖,那么就不要用#import。若因為要實現(xiàn)屬性马篮、實例變量或者要遵循協(xié)議而必須引入頭文件沾乘,則應(yīng)盡量將其移至“class-continuation分類中”。這樣做不僅可以縮減編譯時間浑测,而且還能降低彼此依賴程度翅阵。
3、多用字面量語法迁央,少用與之等價的方法
- 字面數(shù)值
//① 使用方法
NSNumber *someNumber = [NSNumber numberWithInt:1];
//②使用字面量
NSNumber *intNumber = @1;
NSNumber *floatNumber = @2.5f;
NSNumber *boolNumber = @YES;
......
以上定義兩種定義推薦使用第二種掷匠,這樣做可以令NSNumber對象變得整潔。以下定義方式同理岖圈。
- 字面量數(shù)組
//①使用NSArray類方法
NSArray *animals = [NSArray arrayWithObjects:@"cat", @"dog", @"mouse", @"badger", nil];
//②使用字面量
NSArray *animals = @[@"cat", @"dog", @"mouse", @"badger"];
//從數(shù)組中取值
//①使用objectAtIndex
NSString *dog = [animals objectAtIndex: 1];
//②使用字面量
NSString *dog = animals[1];
下面代碼分別以兩種語法創(chuàng)建數(shù)組:
id object1 = /* ... */;
id object2 = /* ... */;
id object3 = /* ... */;
//①使用NSArray類方法
NSArray *arrayA = [NSArray arrayWithObjects:object1, object2, object3, nil];
//②使用字面量
NSArray *arrayB = @[object1, object2, object3];
如果object1和object3都指向了有效的Objective-C對象讹语,而object2是nil。按字面量語法創(chuàng)建數(shù)組arrayB時會拋出異常蜂科。arrayA雖然能創(chuàng)建出來募强,但是其中卻只包含object1一個對象。原因在于崇摄,“arrayWithObjects:”方法會依次處理各個參數(shù)擎值,知道發(fā)現(xiàn)nil為止。這個差別表明逐抑,使用字面量語法更為安全鸠儿。
- 字面量字典(與數(shù)組差不多)
//這樣寫的順序是<對象>,<鍵>厕氨,<對象>进每,<鍵>。這很不容易理解命斧。
NSDictionary *personData = [NSDictionary dictionaryWithObjectsAndKeys:@"Matt", @"firstName", @"Galloway", @"lastName", [NSNumber numberWithInt:28], @"age", nil];
//使用字面量語法田晚,就一目了然了
NSDictionary *personData = @{
@"firstName" : @"Matt",
@"lastName" : @"Galloway",
@"age" : @28
};
與數(shù)組一樣,用字面量語法創(chuàng)建字典時也有個問題国葬,那就是一旦有值為nil贤徒,便會拋出異常。
取值時也推薦使用字面量語法
NSString *fisrstName = personData[@"firstName"];
字面量語法的局限性
- 除了字符串以外汇四,所創(chuàng)建出來的對象必須屬于Foundation框架才行接奈。如果自定義了這些類的子類,則無法用字面量語法創(chuàng)建其對象通孽。
- 創(chuàng)建字符串時可以使用自定義的子類序宦,然而必須要修改編譯器的選項才行。但一般不鼓勵使用此選項背苦,用NSString就足夠了互捌。
- 使用字面量語法創(chuàng)建出來的字符串潘明、數(shù)組、字典對象都是不可變的(immutable)秕噪。若想要可變版本的對象钳降,則需要復(fù)制一份:
NSMutableArray *mutable = [@[@1, @2, @3, @4, @5] mutableCopy];
//這么做會多調(diào)用一個方法,而且還要再創(chuàng)建一個對象巢价,不過使用字面量語法所帶來的好處還是要多余上述缺點的
4、多用類型常量固阁,少用#define預(yù)處理指令
比我們需要定義一個固定的動畫時間壤躲,用#define預(yù)處理指令可以這樣寫:
#define ANIMATION_DURATION 0.3
預(yù)處理過程中會把碰到的所有ANIMATION_DURATION一律替換成0.3,這樣的話备燃,假設(shè)此指令聲明在某個頭文件中碉克,那么所有引入 了這個頭文件的代碼,其//ANIMATION_DURATION都會被替換并齐。
要想解決此問題漏麦,應(yīng)該設(shè)法利用編譯器的某些特性才對。有個辦法比用預(yù)處理指令來定義常量更好况褪。比方說:
//此方式定義的常量包含類型信息撕贞,其好處是清楚地描述了常量的含義。由此可知該常量類型為NSTimeInterval测垛,這有助于編寫開發(fā)文檔
static const NSTimeInterval kAnimationDuration = 0.3;
- 常用的命名法則是: 若常量局限于某“編譯單元”(translation unit捏膨,也就是“實現(xiàn)文件”, implementation file)之內(nèi)食侮,則在前面加字母k号涯;若常量在類之外,則通常以類名為前綴锯七。
- 定義常量的位置很重要链快,ANIMATION_DURATION這個常量名就不應(yīng)該用在頭文件中,因為所有引入了這份文件的其他文件都會出現(xiàn)這個名字眉尸。static const定義的常量也不應(yīng)該出現(xiàn)在頭文件里域蜗。因為Objective-C沒有”命名空間“這一概念,所以那樣做等于聲明 了一個名為kAnimationDuration的全局變量噪猾。此名稱應(yīng)該加上前綴地消,以表明其所屬的類。
- static 修飾的變量若要在當前編譯單元以外可見畏妖,則要和extern結(jié)合使用脉执。在頭文件中使用extern來聲明全局常量,并在相關(guān)實現(xiàn)文件中定義其值戒劫。這種常量要出現(xiàn)在全局符號表中半夷,所以其名稱應(yīng)加以區(qū)分婆廊,通常用與之相關(guān)的類名做前綴。
5巫橄、用枚舉表示狀態(tài)淘邻、選項、狀態(tài)嗎
- enum湘换。系統(tǒng)框架中頻繁用到此類型宾舅,然而開發(fā)者很容易忽視它。在一系列常量來表示錯誤狀態(tài)碼或課組合的選項時彩倚,極宜使用枚舉為期命名筹我。由于C++11標準擴充了枚舉的特性,所以最新版系統(tǒng)框架使用了“強類型”(strong type)的枚舉帆离,Objective-C也能得益于C++11標準蔬蕊。
- 應(yīng)該用枚舉來表示狀態(tài)機的狀態(tài)、傳遞給方法的選項以及狀態(tài)碼等值哥谷,給這些值起個容易懂得名字岸夯。
- 如果把傳遞給某個方法的選項表示為你枚舉類型,而多個選項又可以同時使用们妥,那么就將各選項值定義為2的冪猜扮,以便通過安位操作將其組合起來。