第1章 熟悉Objective-C
第1條:了解Objective-C語言的起源
- Objective-C為C語言添加了面向物件的特性,是其超集,Objective-C使用動態系結的訊息結構,也就是說在運行時才會檢查物件型別,接受一條訊息之后,究竟應執行何種代碼,由運行期環境而非編譯器來決定,
第2條:在類的頭檔案中盡量少引入其他頭檔案
- 在編譯一個需要使用B類的A類檔案時,當不需要知道B類的全部細節,只需要在知道B類的類名就好,可以使用“向前宣告”(forward declaring)該類
@class B;
- 向前宣告也可以解決特定場合下的回圈參考(互相參考)
- 有時無法使用向前宣告,比如宣告某個類遵循一項協議,在這種情況下,盡量把“該類遵循某協議”的這條宣告移至“class-contination”分類中,如果不行的話,就把協議單獨放在一個頭檔案中,然后將其引入
第3條:多用字面量語法,少用與之等價的方法
- 應該使用字面量語法來創建字串、數值、陣列、字典,與創建此類物件的常規方法相比,這么做更簡明扼要
- 應該通過取下標操作來訪問陣列下標或字典中的鍵所對應的元素
- 用字面量語法創建陣列或字典時,若值中有nil,則會拋出例外,因此務必確保值中里,不含nil
例如:
NSSAray *arrayA = [NSArray array WithObjects: object1,object2, object3, nil];
NSSArray *arrayA = @[object1, object2, object3];
其中object2時nil,創建arrayB 時會拋出例外,arrayA雖然能創建出來,但是其中卻只含有object1一個物件,原因在于,“arrayWithObjects:”方法會依次處理各個引數,直到發現nil為止,由于object2是nil,所以該方法會提前結束,
第4條:多用型別常量,少用#define預處理命令
- 不要用預處理指令定義常量,這樣定義出來的常量不含型別資訊,編譯器只是會在編譯前據此執行查找與替換操作 ,即使有人重新定義了常量值,編譯器也不會產生警告資訊,這將導致應用程式中的常量值不一致,
- 在實作檔案中使用
static const來定義 “只在編譯單元內可見的常量”(translation-unit-specific contant),由于此類常量不在全域符號表中,所以無需為其名稱加前綴,static const NSTimerInterval kAnimationDuration = 0.3;// 通常以k開頭 - 在頭檔案中使用extern 來定義宣告全域常量,并在相關實作檔案中定義其值,這種常量要出現在全域符號表中,所以其名稱應加以區隔,通常用與之相關的類名作前綴,
// EOCAnimatedView.h 通常用與之相關的類名作前綴
extern const NSTimerInterval EOCAnimatedViewAnimationDuration;
// EOCAnimatedView.m
const NSTimerInterval EOCAnimatedViewAnimationDuration = 0.3;
第5條: 用列舉表示狀態、選項、狀態碼
- 應該用列舉來表示狀態機的狀態、傳遞給方法的選項以及狀態碼等值,給這些值起個易懂的名字,
- 如果把傳遞給某個方法是的選項表示為列舉型別,并指明其底層資料型別,而多個選項又可同時使用,那么就將各選項值定義為2的冪,以便通過按位或操作將其組合起來
例如,iOS UI框架中有如下列舉型別,用來表示某個視圖應該如何在水平或垂直方向上調整大小:
// 定義列舉
enum UIViewAutoresizing {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5,
}
// 用“按位與運算子”(bitwise AND operator)即可判斷出是否已啟用某個選項
enum UIViewAutoresizing resizing =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
if (resizing & UIViewAutoresizingFlexibleWidth) {
//UIViewAutoresizingFlexibleWidth is set
}
- 用NS_ENUM 與 NS_OPTIONS 宏來定義列舉型別, 并指明其底層資料型別,這樣可以確保列舉是用開發者所選的底層資料型別實作出來的,而不會采用編譯器所選的資料型別,
- 作為選項的列舉值經常需要用按位或運算來組合,在用或運算操作兩個列舉值時,C++認為運算結果的資料型別應該是列舉的底層資料型別,也就是NSUInteger,而且C++不允許將這個底層型別“隱式轉換”(implicit cast)為列舉型別本身,按NS_ENUM方式將其展開(以書中EOCPermittedDirection來演示)
//按NS_ENUM方式展開
typedef enum EOCPermittedDirection : int EOCPermittedDirection;
enum EOCPermittedDirection : int {
EOCPermittedDirectionUp = 1 << 0;
EOCPermittedDirectionDown = 1 << 1;
EOCPermittedDirectionLeft = 1 << 2;
EOCPermittedDirectionRight = 1 << 3;
};
//然后考慮以下代碼
EOCPermittedDirection perttedDirections =
EOCPermittedDirectionLeft | EOCPermittedDirectionUp;
/*
若按C++模式編譯(也可能是按Objective-C++模式編譯),則會給出下列錯誤資訊:
error : cannot initialize a variable of type
'EOCPermittedDirection' with an rvalue of type 'int'
如果想編譯這行代碼,就要將按位或操作的結果顯式轉換(expictcast)為
EOCPermittedDirection,
*/
所以,在C++模式下應該用另一種方式定義NS_OPTIONS宏,以便省去轉換操作,鑒于此,凡是需要以按位或操作來組合的列舉都應使用NS_OPTIONS定義,若是列舉不需要互相組合,則應使用NS_ENUM來定義,
- 在處理列舉型別的switch陳述句中不要實作default分支,這樣的話,加入新的列舉之后,編譯器就會提示開發者:swtich陳述句并未處理所有列舉,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/292204.html
標籤:其他
