? ? ? 最近打算把Effective Objective-C 2.0重新再精讀一遍冈涧,所以在此留下筆記殊者,一方面是監(jiān)督自己能堅(jiān)持下去太雨,不能像第一遍那樣走馬觀花名段,讀過(guò)就忘得差不多了阱扬;另一方面是想把一些好的東西分享給大家。
1.了解Objective-C語(yǔ)言的起源
? ? ? Objective-C語(yǔ)言由smalltalk演化而來(lái)伸辟,該語(yǔ)言使用消息結(jié)構(gòu)而非函數(shù)調(diào)用麻惶。關(guān)鍵區(qū)別在于:使用消息結(jié)構(gòu)的語(yǔ)言,其運(yùn)行時(shí)所執(zhí)行的代碼由運(yùn)行環(huán)境決定信夫,而使用函數(shù)調(diào)用的語(yǔ)言窃蹋,則由編譯器決定卡啰。
? ? ? ? Objective-C的重要工作都由“運(yùn)行期組件”來(lái)完成,因此警没,只需要更新運(yùn)行期組件匈辱,即可提升應(yīng)用程序性能。Objective-C是C的“超集”杀迹,所以C語(yǔ)言中的所有功能在此依然適用亡脸,因此,必須同時(shí)掌握這兩門語(yǔ)言的核心概念树酪,方能寫出高效的代碼來(lái)浅碾。Objective-C中的指針是用來(lái)指示對(duì)象的锄俄,想要聲明一個(gè)變量晤硕,令其指代某個(gè)對(duì)象林艘,可用如下語(yǔ)法:
? ? ? ? ? ? ? ? ? NSString *someString = @"The string.";
這種語(yǔ)法基本上是照搬C魚呀的阴颖,它聲明了一個(gè)名為someString的變量,其類型是NSString *瞬捕。也就是說(shuō)此變量為指向NSString的指針虱疏。所有Objective-C語(yǔ)言的對(duì)象都必須這樣聲明毒涧,因?yàn)閷?duì)象所占內(nèi)存總是分配在“堆空間”中力试,而不會(huì)分配在“椺懔冢”上。
2.在類的頭文件中盡量少引入其他頭文件
? ? ? ? 將引入頭文件的時(shí)機(jī)盡量延后畸裳,只在確有需要時(shí)才引入鹃栽,這樣就可以減少類的使用者所需要引入的頭文件數(shù)量,避免引入許多根本用不到的內(nèi)容躯畴,增加編譯時(shí)間。一般來(lái)說(shuō)薇芝,應(yīng)在某個(gè)類的頭文件中使用向前聲明"@class 類名" 來(lái)提及別的類蓬抄,并在實(shí)現(xiàn)文件中引入那些類的頭文件。這樣做可以盡量降低類之間的耦合夯到。
3.多用字面量語(yǔ)法嚷缭,少用與之等價(jià)的方法
? ? ? ? 在編寫程序時(shí),總會(huì)用到某幾個(gè)類:NSString,NSNumber,NSArray,NSDictionary,它們屬于Foundation框架耍贾。在創(chuàng)建這幾種類型時(shí)阅爽,我們可以選擇使用字面量語(yǔ)法,如:
NSString *someString = @"This is someString.";
NSNumber *someNumber = @1;
NSArray * animals = @[@"cat",@"dog",@"mouse"];
NSDictionary *personData = @{@"firstName":@"Matt",@"lastName":@"Galloway",@"age":@20};
? ? ? ? 另外荐开,我們也可以使用類本身提供的方法來(lái)創(chuàng)建實(shí)例付翁。但是使用字面量語(yǔ)法可以縮短源代碼長(zhǎng)度,使其更為易讀晃听,除此之外百侧,在使用字面量語(yǔ)法創(chuàng)建數(shù)組時(shí)砰识,若數(shù)組元素對(duì)象中有nil,則會(huì)拋出異常,因?yàn)樽置媪空Z(yǔ)法實(shí)際上只是一種“語(yǔ)法糖”佣渴,其效果等于先創(chuàng)建了一個(gè)數(shù)組辫狼,然后把方括號(hào)內(nèi)的所有對(duì)象都加到這個(gè)數(shù)組中。下面這段代碼分別以兩種語(yǔ)法創(chuàng)建數(shù)組:
id object1 = /*..*/;
id object2 = /*..*/;
id object3 = /*..*/;
NSArray *arrayA = [NSArray arrayWithObjects:object1,object2,object3,nil];
NSArray *arrayB = @[object1,object2,object3];
如果object2是nil辛润,其他兩個(gè)對(duì)象都是有效的OC對(duì)象膨处。那會(huì)出現(xiàn)什么情況呢?按字面量語(yǔ)法創(chuàng)建數(shù)組的arrayB會(huì)拋出異常,拋出的異常會(huì)是這樣:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[1]'砂竖。
arrayA雖然能創(chuàng)建出來(lái)真椿,但是其中卻只含有一個(gè)對(duì)象。原因在于晦溪,“arrayWithObjects:”方法會(huì)依次處理各個(gè)參數(shù)瀑粥,直到發(fā)現(xiàn)nil為止,由于object2是nil三圆,所以該方法會(huì)提前結(jié)束狞换。
? ? ? ? 這個(gè)微妙的差別表明,使用字面量語(yǔ)法更為安全舟肉。拋出異常令程序終止執(zhí)行修噪,這比創(chuàng)建好數(shù)組后才發(fā)現(xiàn)元素少了要好。
? ? ? ? 與數(shù)組一樣路媚,用字面量語(yǔ)法創(chuàng)建字典時(shí)也有這個(gè)問(wèn)題黄琼,那就是一旦有值為nil,便會(huì)拋出異常整慎。不過(guò)基于同樣的原因脏款,這也是好事。假如創(chuàng)建字典時(shí)不小心用了空值對(duì)象裤园,那么"dictionaryWithObjectsAndKeys:"方法就會(huì)在首個(gè)nil之前停下撤师,并拋出異常,這有助于查錯(cuò)拧揽。
4.多用類型常量剃盾,少用#define預(yù)處理指令
編寫代碼時(shí)經(jīng)常要定義常量。例如淤袜,定義一個(gè)播放動(dòng)畫時(shí)間:
#define ANIMATIONDUARTION 0.3
? ? ? ? 上述預(yù)處理指令會(huì)把源代碼中的ANIMATIONDUARTION字符串替換為0.3,這可能就是你想要的效果痒谴,不過(guò)這樣定義出來(lái)的常量沒(méi)有類型信息,而且即使有人重新定義了常量值铡羡,編譯器也不會(huì)產(chǎn)生警告信息积蔚,這將導(dǎo)致應(yīng)用程序中的常量值不一致。若是此指令聲明在某頭文件中烦周,那引入該頭文件的代碼库倘,ANIMATIONDUARTION都將被替換临扮。有個(gè)辦法,就比用預(yù)處理指令來(lái)定義常量更好:
static const NSTimeInterval kAnimationDuration = 0.3;
請(qǐng)注意教翩,用此方式定義的常量包含類型信息杆勇,其好處是清楚地描述了常量的定義。由此可知該常量類型饱亿,這有助于為其編寫開(kāi)發(fā)文檔蚜退。如果要定義許多常量,那么這種方式能令稍后閱讀代碼的人更易理解其意圖彪笼。常量的命名法是:若常量局限于某“編譯單元”钻注,也就是實(shí)現(xiàn)文件之內(nèi),則在前面加字母k配猫,若常量在類之外可見(jiàn)幅恋,則通常以類名為前綴。
? ? ? ?變量一旦同時(shí)用static與const來(lái)聲明泵肄,如果試圖修改由const修飾符所聲明的變量捆交,那么編譯器就會(huì)報(bào)錯(cuò)。而static修飾符則意味著該變量?jī)H在定義此變量的編譯單元中可見(jiàn)腐巢。假如此變量前不加static品追,則編譯器會(huì)為它創(chuàng)建一個(gè)“外部符號(hào)”。此時(shí)若是另一個(gè)編譯單元中也聲明了同名變量冯丙,那么編譯器就會(huì)拋出一條錯(cuò)誤信息肉瓦。如果需要對(duì)外公開(kāi)某個(gè)常量,則可用以下方式胃惜,在.h文件中聲明:extern NSString *const EOCStringConstant;
在.m文件中定義:NSString *const EOCStringConstant = @"VALUE";
這種常量要出現(xiàn)在全局符號(hào)表中泞莉,所以其名稱應(yīng)加以區(qū)隔,通常用與之相關(guān)的類名做前綴船殉。
5.用枚舉表示狀態(tài)戒财,選項(xiàng),狀態(tài)碼
? ? ? ?應(yīng)該用枚舉來(lái)表示狀態(tài)機(jī)的狀態(tài)捺弦,傳遞給方法的選項(xiàng)以及狀態(tài)碼等值,給這些值起個(gè)易懂的名字孝扛。
? ? ? ?如果把傳遞給某個(gè)方法的選項(xiàng)表示為枚舉類型列吼,而多個(gè)枚舉選項(xiàng)又可同時(shí)使用,那么就將各選項(xiàng)值定義為2的冪苦始,以便通過(guò)按位或操作將其組合起來(lái)寞钥。
? ? ? ? 用NS_ENUM 與 NS_OPTIONS宏來(lái)定義枚舉類型,并指明其底層數(shù)據(jù)類型陌选。這樣做可以確保枚舉是開(kāi)發(fā)者所選的底層數(shù)據(jù)類型實(shí)現(xiàn)出來(lái)的理郑,而不會(huì)采用編譯器所選的類型蹄溉。
? ? ? 在處理枚舉類型的switch語(yǔ)句中不要實(shí)現(xiàn)default分支,這樣的話您炉,加入新枚舉之后柒爵,編譯器就會(huì)提示開(kāi)發(fā)者:switch語(yǔ)句并未處理所有枚舉。