1. 程式人生 > >Effective Objective-C 2.0 編寫高質量iOS與OS X程式碼的52個有效方法(一)

Effective Objective-C 2.0 編寫高質量iOS與OS X程式碼的52個有效方法(一)

1. 使用訊息結構的語言,其執行時所應執行的程式碼由執行環境來決定;而使用函式呼叫的語言,則由編譯器來決定。 如果範例程式碼呼叫的函式是多型的,則執行時根據虛擬函式表來查出應該執行哪個函式實現。 而採用訊息結構的語言,不論是否多型,總是在執行時才會去查詢所要執行的方法。 接受訊息的物件問題也要在執行時處理,其過程叫“動態繫結(dynamic binding)”。 2.【在類的標頭檔案中儘量少引入其他標頭檔案】 ① 除非確有必要,否則不要引入標頭檔案,一般來說,應在某個類的標頭檔案中使用“向前宣告”提及別的類,並在實現檔案中引入那些類的標頭檔案,這樣做可以儘量降低類之間的耦合(coupling); ② 有時無法使用向前宣告,比如要宣告某個類遵循一項協議。這種情況下,儘量把“該類遵循某協議”的這條宣告移至“class—continuation分類”。如果不行,則把協議單獨放在一個頭檔案裡面,將其引入。 ③ 延遲引入標頭檔案的時機,減少類的使用者所需引入的標頭檔案數量,減少編譯時間,減少互相引用。 3.【多用字面量語法,少用與之等價的方法】 ①
NSNumber *number = [NSNumber numberWithInt:1];
//字面量寫法:
NSNumber *number = @1;
NSNumber *doubleNumber = @3.14159;
NSNumber *boolNumber = @yes;
NSNumber *charNumber = @‘a’;
甚至適用於表示式:
int x = 5;
float y = 6.23f;
NSNumber *expressNumber = @(x * y);

② 字面量陣列
NSArray *animals = [NSArray arrayWithObjects:@“cat”, @“dog”, @“mouse”, @“badger”, nil];
// 使用字面量:
NSArray *animals = @[@“cat”, @“dog”, @“mouse”, @“badger”];
注:使用字面量語法建立陣列,若陣列元素物件中有nil,則會丟擲異常。 因為字面量語法實際上是一種“語法糖”;其效果相當於先建立一個數組,然後將括號裡面的所有物件都加到這個陣列。 例如:
NSArray *arr1 = [NSArray arrayWithObjects:object1, object2, object3, nil];
NSArray *arr2 = @[object1, object2, object3];

假若object2是nil。arr1可以創建出來,卻只有一個元素。 而arr2 則會丟擲異常。這比建立好了陣列後發現元素個數少了要好。通過異常可以快速發現這個錯誤。 ③ 字面量字典
NSDictionary *person = [NSDictionary dictionaryWithObjectAndKeys:@“matt”,@“first name”,@“galloway”, @“lastName”,nil];
// 使用字面量:
NSDictionary *person = @{@“first name”:@“matt”, @“lastName”:@“galloway”};
鍵在值前面。 訪問的時候:
NSString *lastName = [person objectForKey:@“lastname”];
NSString *lastName = person[@“lastname”];
④ 侷限性 使用字面量創建出來的字串、陣列、字典物件都是不可變的。 4. 【多用型別常量,少用#define預處理指令】 ① 不要用預處理指令定義常量。這樣定義出來的常量不含型別資訊。編譯器只是會在編譯前據此執行查詢與替換而已。 即使有人重新修改了常量值,編譯器不會報錯。這會導致程式裡面的常量值不一致。 ② 在實現檔案中使用static const 來定義“只在編譯單元內可見的常量”,由於此類常量不在全域性符號表中,所以無須為其名稱加字首。 const修飾為常量。static限制為該變數僅在定義此變數的編譯單元中可見。 ③ 在標頭檔案用extern來宣告全域性常量,並在相關實現檔案中定義其值。這種常量要出現在全域性符號表中。所以名稱要用與之相關的類名做字首。 5. 【用列舉表示狀態、選項、狀態碼】 ① 如果把傳遞給某個方法的選項表示為列舉型別,而多個選項又可同時使用,那麼就將各選項值定義為2的冪,以便通過按位或操作將其組合起來。 ② 用 NS_ENUM 和 NS_OPTIONS 巨集來定義列舉型別,並指明其底層資料型別。這樣做可以確保列舉是用開發者所選的底層資料型別實現出來的。而不會採用編譯器所選的型別。
typedef NS_ENUM(NSUInteger, EOCConnectionState) {
     EOCConnectionStateDisconnected,
     EOCConnectionStateDisconnected,
     EOCConnectionStateDisconnected
};
typedef NS_OPTIONS(NSUInteger, EOCPermittedDirection) {
     EOCCPermittedDirectionUp = 1 << 0,
     EOCCPermittedDirectionDown = 1 << 1,
     EOCCPermittedDirectionLeft = 1 << 2,
     EOCCPermittedDirectionRight = 1 << 3,
};

③ 在處理列舉型別的switch 語句中不要實現default分支,這樣加入新的列舉型別後,編譯器就會提示開發者,switch語句並未處理所有的列舉。 ④ 可以指明用何種“底層資料型別”來儲存列舉型別的變數。這樣做的好處是,可以向前宣告列舉變量了。若不指定底層資料型別,則無法向前宣告列舉型別。因為編譯器不清楚資料型別的大小。所以在用到此列舉型別時,也就不知道究竟該給變數分配多少空間了。
enum EOCConnectionState connectionState : NSInteger { // };