Effective Objective-C 2.0 學習筆記(1)

第一條 瞭解Objective-C預言起源

起源:Smalltalk

類型:使用消息結構的語言

區別:使用消息結構的語言,其運行時所應執行的代碼由運行環境來決定;而使用函數調用的語言則由編譯器決定。

對象分配在堆空間上,指針分配在棧空間上

結構體分配在棧空間(CGRect)

第二條 在類的頭文件中儘量少引入其他頭文件

用OC編寫任何類幾乎都需要引入Foundation.h。

向前聲明:@class EOCEmployer;

使用#import而非#include互相引用時不會死循環

要點:

1、除非有必要,不要引入頭文件。應在類的頭文件中使用向前聲明來提及別的類,在實現文件中引入那個類的頭文件。可以儘量降低類之間的耦合。

2、無法使用向前聲明,如聲明某個類遵循一項協議。儘量把“遵循某協議”的聲明移到“class-continuation分類”中。若不行,就把協議單獨放在一個頭文件中,再引入。

第三條 多用字面量語法,少用與之等價的方法

字面量語法只是一種“語法糖”

疑問:mrc下字面量創建的對象到底有沒有reatain+1

使用字面量語法創建出來的字符串、數組、字典對象都是不可變的,若想要可變版本的對象,需要複製一份

要點:

1、使用字面量語法來創建字符串、數值、數組、字典。

2、通過取下標操作來訪問數組下標或字典中的鍵所對應的元素

3、用字面量語法創建數組或字典時,若值中有nil,則會拋出異常。因此,務必確保值裡不含nil

第四條 多用類型常量,少用#define 預處理指令

#define ANIMATION_DURATION 0.3
static const NSTimeInterval kAnimationDuration = 0.3;

若不打算公開某個常量,則應將其定義在使用該常量的實現文件裡。static修飾符意味著該變量僅在定義此變量的編譯單元可見。在OC語境下,“編譯單元”指每個類的實現文件(以.m為後綴名)。假如聲明此變量時不加static,則編譯器會為它創建一個“外部符號”。此時若是另一個編譯單元中也聲明瞭同名變量,那麼編譯器就會拋出錯誤。

如果一個變量既聲明為static,又聲明為const,編譯器根本不會創建符號,而是會像#define一樣,把所遇到的變量都替換成常值。

常量放在“全局符號表中”:

//In the header file
extern NSString *const EOCStringConstant;
//In the implementation file
NSString *const EOCStringConstant = @"VALUE";
Effective Objective-C 2.0 學習筆記(1)

第五條 用枚舉表示狀態、選項、狀態嗎

要點:

如果把傳遞給某個方法的選項表示為枚舉類型,而多個選項又可同時使用,那麼就將各選項值定義為2的冪,以便通過按位或操作將其組合起來。

用NS_ENUM與NS_OPTIONS宏定義枚舉類型,並指明底層數據類型。這樣可以確保枚舉是用開發者所選的底層數據類型實現出來,而不會採用編譯器所選的類型。

在處理枚舉類型的switch語句中不要實現default分支。這樣的話,加入新枚舉之後,編譯器就會提示開發者:switch語句並未處理所有枚舉。

第六條 理解 “屬性” 這一概念

編譯器會把“點語法”轉換為對存取方法的調用,使用“點語法”的效果與直接調用存取方法相同。

如果使用了屬性,編譯器會自動編寫訪問這些屬性所需的方法,此過程叫“自動合成(autosynthesis)”。這個過程由編譯器在編譯期執行,所以編輯器裡看不到“合成方法(synthesied method)”的源代碼。除了生成方法代碼,編譯器還要自動向類中添加適當類型的實例變量,並且在屬性名前面加下劃線,以此作為實例變量的名字。也可以在類的實現代碼裡通過@synthesize語法來指定實例變量的名字

@implementation EOCPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end

有一種辦法能阻止編譯器自動合成存取方法,就是使用@dynamic關鍵字,它會告訴編譯器:不要自動創建實現屬性所用的實例變量,也不要為其創建存取方法。而且,在編譯訪問屬性的代碼時,即使編譯器發現沒有定義存取方法,也不會報錯,它相信這些方法能在運行期找到。

@interface EOCPerson : NSManagedObject
@property NSString *firstName;
@property NSString *lastName;
@end
@implementation EOCPerson
@dynamic firstName, lastName;
@end

屬性的特質:原子性,讀/寫權限,內存管理語義,方法名

要點:

用@property語法來定義對象中所封裝的數據

通過“特質”來指定存儲數據所需的正確語義

在設置屬性所對應的實例變量時,一定要遵從該屬性所聲明的語義

開發iOS程序時應該使用nonatomic屬性,因為atomic屬性會嚴重影響性能

第七條 在對象內部儘量直接訪問實例變量

直接訪問實例變量,不會觸發 kvo通知。

在寫入實例變量時,通過設置方法來做,在讀取實例變量時,則直接訪問。

在初始化方法中設置屬性值應該直接訪問實例變量,因為子類可能會覆寫設置方法

delloc中直接通過

惰性化初始技術需要採用存取方法。

第八條 理解“對象等同性” 這一概念

使用NSObject協議中聲明的 isEqual 方法來判斷兩個對象的等同性

NSObject協議中兩個用於判斷等同性的關鍵方法:

- (BOOL)isEqual:(id)object;
- (NSUInterger)hash;

等同性約定

如果 isEqual: 判定兩個對象相等,那麼hash方法也必須返回同一個值.但是,如果兩個對象的hash方法返回同一個值, isEqual: 未必會認為兩者相等

有一種情況要注意,在容器中放入可變類對象時,把某個對象放入collection之後,就不應再改變其哈希碼了。

要點:

若想檢測對象的等同性,請提供“isEquel:”與hash方法

相同的對象必須具有相同的哈希碼,但是兩個哈希碼相同的對象卻未必相同

第九條 以“類族模式”隱藏實現細節

類族可以隱藏“抽象基類”背後的實現細節。

系統框架有很多類族。大部分collection類都是類族。

在傳統的類族模式中,通常只有一個類具備“公共藉口”,這個類就是類族中的抽象基類

Cocoa中NSArray這樣的類族來說,新增子類需遵守幾條規則:

自類應該繼承自類族中的抽象基類

子類應該定義自己的數據存儲方式

子類應當覆寫超類文檔中指明需要覆寫的方法

第十條 在既有類中使用關聯對象存放自定義數據

Effective Objective-C 2.0 學習筆記(1)

設置關聯對象

void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)

取關聯對象值

id objc_getAssociatedObject(id object, void *key)

移除指定對象的全部關聯對象

void objc_removeAssociatedObjects(id object)

要點

定義關聯對象可指定內存管理語義,用以模仿定義屬性時所採用的“擁有關係”與“非擁有關係”

只有在其他做法不可行時才應選用關聯對象,因為這種做法通常會引入難於查找的bug



分享到:


相關文章: