Effective Objective-C 2.0隨身筆記(一)

(注:該筆記適用于結(jié)合Effective Objective-C 2.0這本書一起看,筆者只是整理了其中的知識(shí)點(diǎn),細(xì)致的地方還望大家在原著上查看,還望能幫助到大家)

一. 熟悉Objective-C

1.OC語言的起源

OC使用的是“消息結(jié)構(gòu)”而不是“函數(shù)調(diào)用”。


消息與函數(shù)調(diào)用之間的區(qū)別:使用消息結(jié)構(gòu)的語言,其運(yùn)行時(shí)所執(zhí)行的代碼由運(yùn)行環(huán)境來決定;使用函數(shù)調(diào)用的語言,則由編譯器決定。


OC的重要工作都由“運(yùn)行期組件”而非編譯器來完成。


“運(yùn)行期組件”的本質(zhì)就是一種將開發(fā)者所編代碼相鏈接的“動(dòng)態(tài)庫”。


NSString *str = @"string";

它聲明了一個(gè)名為str的變量,其類型為NSString*,也就是說此變量為指向NSString的指針。所有OC語言的對(duì)象都必須這樣聲明,因?yàn)?b>對(duì)象所占的內(nèi)存總是分配在“堆空間”中,而絕不會(huì)分配在“?!鄙?/b>。如果這時(shí)再創(chuàng)建一個(gè)變量指向同一個(gè)地址,那么并不拷貝該對(duì)象,只是這兩個(gè)變量會(huì)同時(shí)指向此對(duì)象。


分配在棧中的內(nèi)存會(huì)在棧幀彈出時(shí)自動(dòng)清理,而分配在堆中的內(nèi)存則被抽象出來,也就是我們常叫的“引用計(jì)數(shù)”。

2.在類的頭文件中盡量少引用其他頭文件

將引入頭文件的時(shí)機(jī)盡量推延,只有在確切需要使用時(shí)才引入,這樣可以減少類的使用者所需引入頭文件的數(shù)量。

方法:在頭文件“向前聲明”該類;#import "xx" 改用為 @class xx;然后在實(shí)現(xiàn)文件再#import "xx"。

3.多用字面量語法,少用與之等價(jià)的方法

比如:NSNumber *num = @1; ? ? int x = 5; ? ? NSArray *arr = @[@"one",@"two"]; ? ??NSString *one = arr[0]; ? ? NSDictionary *dic = @{@"one":@"1",@"two":@"2"}; ? ? NSString *one = dic[@"one"];

注意:用字面量語法創(chuàng)建數(shù)組或者字典時(shí),若值中有nil,則會(huì)拋出異常。因?yàn)檎垊?wù)必確保值里不含nil。

4.多用類型常量,少用#define預(yù)處理指令

定義常量時(shí),我們有時(shí)會(huì):#define ANIMATION_DURATION 0.3

可以換成:static const NSTimeInterval kAnimationDuration = 0.3;

這種寫法更清楚描述了常量的含義和所用到的類型。static修飾符意味著改變了僅在定義此變量的編譯單元內(nèi)可見,const則是不允許此常量被修改。

命名規(guī)范:若常量局限于某“編譯單元”之內(nèi),則在前面加字母k;若常量在類之外可見,則通常以類名為前綴。


如果需要對(duì)外公開某個(gè)變量,比如要派發(fā)通知需要此通知的名稱常量,可以這樣定義:

在頭文件中extern NSString *const EOCStringConstant;

在實(shí)現(xiàn)文件中NSString *const EOCStringConstant = @"VALUE";

5.用枚舉表示狀態(tài)、選項(xiàng)、狀態(tài)碼

enum EOCConectionState{

EOCConectionStateConnecting,

EOCConectionStateDisconnected,

}

二、對(duì)象、消息、運(yùn)行期

6.理解“屬性”這一概念

“屬性”是OC的特性,用于封裝對(duì)象中的數(shù)據(jù)。OC對(duì)象通常會(huì)把其所需要的數(shù)據(jù)保存為各種實(shí)例變量,其中getter用于讀取變量值,setter用于寫入變量值。


@property語法來定義對(duì)象中所封裝的數(shù)據(jù),其意思是:編譯器會(huì)自動(dòng)寫出一套存取方法,用以訪問給定類型具有給定名稱的變量。訪問屬性可以通過“點(diǎn)語法”,效果跟直接調(diào)用存取方法一致。

比如:@property NSString *firstName;

相當(dāng)于-(NSString *)firstName;

-(void)setFirstName:(NSString *)firstName;

屬性特性

原子性、讀/寫權(quán)限、內(nèi)存管理語義、方法名

1.基本所有屬性都要聲明為nonatomic,因?yàn)槿绻褂胊tomic在iOS上開銷較大,會(huì)帶來性能問題,而且atomic也并不能保證“線程安全”,若要保證線程安全則需要采用更深層的鎖定機(jī)制,但在Mac OSX程序上,atomic并不會(huì)有性能瓶頸。

2.具有readwrite特性的屬性有g(shù)etter和setter方法,如果是readonly特性的屬性只有g(shù)etter方法。

3.assign針對(duì)純量類型(CGFloat、NSInteger等);

strong表明該屬性定義了一種“擁有關(guān)系”,為這個(gè)屬性設(shè)置新值時(shí)會(huì)先保留新值并釋放舊值,再將新值設(shè)置上去;

weak表明該屬性定義了一種“非擁有關(guān)系”,為這種屬性設(shè)置新值時(shí),設(shè)置方法既不保留新值也不釋放舊值,特性跟assign一樣,然而在屬性所指向的對(duì)象被摧毀時(shí),屬性值也會(huì)被置空nil;

unsafe_unretained特性和assign相同,但是它適用于“對(duì)象類型”,該特性表明了一種“非擁有關(guān)系”(unretained),當(dāng)目標(biāo)對(duì)象被摧毀,屬性值是不會(huì)被置空nil(unsafe);

copy特性和strong類似,然而設(shè)置方法并不保留新值,而是將其拷貝,常用于NSString來保護(hù)其封裝性。因?yàn)閭鬟f給設(shè)置方法的新值有可能指向一個(gè)NSMutableString類的實(shí)例,這個(gè)類是NSString的子類,可以修改其值的字符串,若此時(shí)不拷貝字符串就有可能被修改,所以只要實(shí)現(xiàn)屬性所用的對(duì)象是可變的,就應(yīng)該在設(shè)置新屬性時(shí)拷貝一份。

4.getter=<name>指定“獲取方法”的方法名:

@property(nonatomic, getter=isOn)BOOL on;


setter = <name>“設(shè)置方法”的方法名:

-(id)initWithFirstName:(NSString *)firstName{

if(self = [super init]){

_firstName = [firstName copy];

}

}

7.在對(duì)象內(nèi)部盡量直接訪問實(shí)例變量

通過屬性訪問和直接訪問實(shí)例變量有以下區(qū)別:

(一)直接訪問實(shí)例變量速度更快,編譯器所生成的代碼會(huì)直接訪問保存對(duì)象實(shí)例變量的內(nèi)存。

(二)直接訪問實(shí)例變量時(shí),不會(huì)調(diào)用其setter方法,這就繞過了為相關(guān)屬性所定義的“內(nèi)存管理語義”。比方說,在ARC下直接訪問一個(gè)聲明copy的屬性,那么并不會(huì)拷貝該屬性,只會(huì)保留新值并釋放舊值。

(三)直接訪問實(shí)例變量不會(huì)觸發(fā)KVO。

(四)通過屬性訪問有助于排查與之相關(guān)的錯(cuò)誤,因?yàn)榭梢栽趃etter和setter中加斷點(diǎn)來調(diào)試。


總結(jié):

1.在對(duì)象內(nèi)部讀取數(shù)據(jù)時(shí),應(yīng)該直接通過實(shí)例變量來讀,而寫入數(shù)據(jù)時(shí),應(yīng)該通過屬性來寫。

2.在初始化以及dealloc方法中,總是應(yīng)該直接通過實(shí)例變量來讀寫數(shù)據(jù)。

3.使用懶加載初始化時(shí),需要通過屬性來讀取數(shù)據(jù),否則實(shí)例變量永遠(yuǎn)不會(huì)初始化。

-(EOCBrain*)brain{

if(!brain){

_brain = [Brain new];

}

}

8.理解“對(duì)象等同性”這一概念

==操作符比較的是兩個(gè)指針的本身,若想檢測對(duì)象的等同性,請?zhí)峁癷sEqual”與hash方法。

相同的對(duì)象必須具有相同的哈希碼,但是兩個(gè)哈希碼相同的對(duì)象卻未必相同。

不要盲目地逐個(gè)檢測每條屬性,而是應(yīng)該依照具體需求來制定檢測方案。

編寫hash方法時(shí),應(yīng)該使用計(jì)算速度快而且哈希碼碰撞幾率低的算法。

9.以“類族模式”隱藏實(shí)現(xiàn)細(xì)節(jié)

類族模式可以把實(shí)現(xiàn)細(xì)節(jié)隱藏在一套簡單的公共接口后面。

Cocoa里面的類族,比如NSArray,NSMutableArray合起來算一個(gè)類族,大部分的collection類都是類族。

創(chuàng)建一個(gè)類族需要枚舉對(duì)象、工廠方法和一套公共的接口,在工廠方法里面根據(jù)不同的枚舉對(duì)象返回不同的子類,其中子類應(yīng)該繼承自類族的抽象基類,子類應(yīng)該定義自己的存取方法,子類應(yīng)該覆寫超類文檔中指明需要覆寫的方法。

10.在既有類中使用關(guān)聯(lián)對(duì)象存放自定義數(shù)據(jù)

可以通過“關(guān)聯(lián)對(duì)象”機(jī)制將兩個(gè)對(duì)象關(guān)聯(lián)起來:

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

objc_getAssociatedObject(id object, void *key)


比如可以應(yīng)用在UIAlertView上,關(guān)聯(lián)block,這樣創(chuàng)建視圖和處理操作的代碼就在一起,比原來更簡單易懂。


注意:這種做法通常會(huì)引入難于查找的BUG。

未完待續(xù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容