編寫高質(zhì)量的代碼

·語法糖:計(jì)算機(jī)語言與另外一套語法等效但是開發(fā)者用起來更加方便的語法打毛。

NSNumer

NSNumber *number = @3.14;
int x = 5;
float y = 6.32f;
NSNumber *expressionNumber = @(x * y);

NSArray

NSArray *animals = @[@"cat", @"dog"];
NSString *dog = animals[1];

屬性:

優(yōu)勢:

編譯器就會自動編寫訪問這些屬性所需的方法驾诈,此過程叫做“自動合成”柠贤。
這個(gè)過程由編譯器在編譯期執(zhí)行,所以編譯器里看不到這些“合成方法”的源代碼。編譯器還自動向類中添加適當(dāng)類型的實(shí)例變量中狂。
@dynamic:
告訴編譯器,不要自動創(chuàng)建實(shí)現(xiàn)屬性所用的實(shí)例變量也不要為其創(chuàng)建存取方法扑毡。
屬性都是nonatomic的:
歷史原因是:在iOS中使用同步鎖的開銷較大胃榕,這會帶來性能問題。而且原子性瞄摊,并不能保證“線程安全”勋又。

對象等同性:

簡介:

當(dāng)且僅當(dāng)“指針值”完全相同時(shí),這兩個(gè)對象才相等换帜。NSObject協(xié)議中有兩個(gè)用于判斷等同性的關(guān)鍵方法:

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

要點(diǎn):

  • 若想檢測對象的等同性楔壤,請?zhí)峁癷sEqual:”與hash方法。
  • 相同的對象必須具有相同的哈希碼惯驼,但是兩個(gè)哈希碼相同的對象卻未必相同蹲嚣。
  • 不要盲目地逐個(gè)檢查每條屬性,而是應(yīng)該依據(jù)具體需求來制定檢測方案祟牲。
  • 編寫hash方法時(shí)隙畜,應(yīng)該使用計(jì)算速度快而且哈希碼碰撞幾率低的算法。

類族

要點(diǎn):

  • 類族模式可以把實(shí)現(xiàn)細(xì)節(jié)隱藏在一套簡單的公共接口后面说贝。
  • 系統(tǒng)框架經(jīng)常使用類族
  • 從類族的公共抽象基類中繼承子類時(shí)要當(dāng)心议惰,若有開發(fā)文檔,則應(yīng)首先閱讀乡恕。

關(guān)聯(lián)對象

設(shè)置關(guān)聯(lián)對象值:

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

根據(jù)給定的鍵從某對象中獲取相應(yīng)的關(guān)聯(lián)對象值:

id objc_getAssociatedObject(id object, void *key)

移除指定對象的全部關(guān)聯(lián)對象:

void objc_removeAssociatedObjects(id object)

應(yīng)用場景:

給系統(tǒng) UIAlertView添加block塊的回調(diào)言询,但是沒有子類話UIAlertView然后在里面封裝的好,所以所以控件最好都自己封裝一下它的內(nèi)部事件几颜。

objc_msgSend

動態(tài)綁定:

調(diào)用的函數(shù)直到運(yùn)行期才能確定倍试。待調(diào)用的函數(shù)地址無法硬編碼到指令之中,而是要在運(yùn)行期讀取出來蛋哭。

給對象發(fā)消息:

id returnValue = [someObject messageName:parameter];
會轉(zhuǎn)換成一條標(biāo)準(zhǔn)的c語言函數(shù)調(diào)用县习,調(diào)用的函數(shù)是消息傳遞機(jī)制中的核心函數(shù),叫做objc_msgSend,其“原型”如下:
void objc_msgSend(id self, SEL cmd, ...)
id returnValue = objc_msgSend(someObject,
                             @selector(messageName:),
                             parameter);

實(shí)現(xiàn)步驟:

在someObject中搜尋其方法列表,如果能找到“messageName”這個(gè)方法躁愿,就跳至其實(shí)現(xiàn)代碼叛本。如果找不到就沿著繼承體系繼續(xù)向上查找,等找到合適的方法之后再跳轉(zhuǎn)彤钟。如果最終還是找不到相符的方法来候,那就執(zhí)行“消息轉(zhuǎn)發(fā)”操作。

弊端:

調(diào)用一個(gè)方法需要很多步驟逸雹。
objc_msgSend會將匹配結(jié)果緩存在“快速映射表(fast map)里面”营搅,每個(gè)類都有這樣一塊緩存,這種“快速執(zhí)行路徑”還是不如“靜態(tài)綁定的函數(shù)調(diào)用操作”那樣迅速梆砸。

實(shí)現(xiàn)流程:

//是否在此類中添加這個(gè)方法
+ (BOOL)resolveInstanceMethod:(SEL)selector;
//能不能把這條消息轉(zhuǎn)給其他接收者來處理转质。
- (id)forwardingTargetForSelector:(SEL)selector;
//如果來到這步,只能啟用完整的消息轉(zhuǎn)發(fā)機(jī)制帖世。首先創(chuàng)建NSInvocation對象休蟹,把尚未處理的那條消息有關(guān)的全部細(xì)節(jié)都封裝其中。
- (void)forwardInvocation:(NSInvocation *)invocation;
消息轉(zhuǎn)發(fā).png

方法互換:

void  method_exchangeImplementations(Method m1, Method m2);

應(yīng)用場景:

可以通過這一手段來為既有的方法實(shí)現(xiàn)增添新功能日矫。

  1. 比方說在調(diào)用lowercaseString的時(shí)記錄某些信息赂弓,這時(shí)就可以通過方法交換來達(dá)成目的。
  2. NSArray里面添加數(shù)組的時(shí)候哪轿,加nil會崩潰盈魁,所以就可以在add方法里面加上空判斷。
    這個(gè)方法最好是不用缔逛,最好是在調(diào)試的時(shí)候使用备埃,很容易出問題姓惑。

獲取方法實(shí)現(xiàn):

Method class_getInstanceMethod(Class aClass, SEL aSelector);

理解“類對象”的用意

簡介:

對象類型并非在編譯器就綁定好了褐奴,而是要在運(yùn)行期查找。
“在運(yùn)行期檢視對象類型”這一操作叫做“類型信息查詢”于毙。

id類型本身定義:

typedef struct objc_object {
  Class isa;
} *id;

isa指針描述了實(shí)例所屬的類敦冬。

isMemberOfClass:能夠判斷出對象是否為某個(gè)特定類的實(shí)例。
isKindOfClass:能夠判斷出對象是否為某類或其派生類的實(shí)例唯沮。

前綴

寫類的時(shí)候要加上命名前綴:

Apple宣稱其保留使用所有“兩字母前綴”的權(quán)利脖旱,所以你自己選用的前綴應(yīng)該是三個(gè)字母的。
需要加前綴的地方:
1)類命
2)分類及分類中的方法
3)純c函數(shù)
4)全局變量

如果應(yīng)用程序自身和其所用的程序庫都引入了同名的第三方庫:

第三方庫應(yīng)該加上前綴以避免命名沖突介蛉。

要點(diǎn):

1.選擇與你的公司萌庆、應(yīng)用程序或二者皆有聯(lián)系之名稱作為類名的前綴,并在所有代碼中均使用這一前綴币旧。
2.若自己所開發(fā)的程序庫中用到了第三方庫践险,則應(yīng)為其中的名稱加上前綴。

全能初始化方法

介紹:令其他初始化方法都來調(diào)用它。只有在這個(gè)方法內(nèi)部才會存儲內(nèi)部數(shù)據(jù)巍虫。這樣的話彭则,當(dāng)?shù)讓訑?shù)據(jù)存儲機(jī)制改變時(shí),只需修改次方法的代碼就好占遥,無須改動其他初始化方法俯抖。

要點(diǎn):

1)在類中提供一個(gè)全能初始化方法,并于文檔里指明瓦胎。其它初始化方法均應(yīng)調(diào)用此方法芬萍。
2)若全能初始化方法與超類不同,則需覆寫超類中的對應(yīng)方法搔啊。
3)如果超類的初始化方法不適用于子類担忧,那么應(yīng)該覆寫這個(gè)超類方法,并在其中拋出異常坯癣。

description

1)實(shí)現(xiàn)description方法返回一個(gè)有意義的字符串瓶盛,用以描述該實(shí)例。
2)若想在調(diào)試時(shí)打印出更詳盡的對象描述信息示罗,則應(yīng)實(shí)現(xiàn)debugDescription方法惩猫。

為私有方法名加前綴

原因:

類的公共API不變隨意改動,私有的API卻可以修改蚜点。
方式:

- (void)p_privateMethod {
/* ... */
}

要點(diǎn):

1)給私有方法的名稱加上前綴轧房,這樣可以很容易地將其同公共方法區(qū)分開。
2)不要單用一個(gè)下劃線做私有方法的前綴绍绘,因?yàn)檫@種做法是預(yù)留給蘋果公司用的奶镶。

理解oc的錯(cuò)誤模型
簡介:

拋出異常,那么本應(yīng)再作用域末尾釋放的對象現(xiàn)在卻不會自動釋放了陪拘。即使用ARC,也很難寫出在拋出異常時(shí)不會導(dǎo)致內(nèi)存泄漏的代碼厂镇。
用處:
異常拋出以后,無需考慮恢復(fù)問題左刽,應(yīng)用程序在此時(shí)應(yīng)該退出捺信。
異常只用于極其嚴(yán)重的錯(cuò)誤。

第26條 勿在分類中聲明屬性
要點(diǎn):

把封裝數(shù)據(jù)所用的全部屬性都定義在主接口里欠痴。
在“class-continuation分類”之外的其他分類中迄靠,可以定義存取方法,但盡量不要定義屬性喇辽。

原因:
1)分類是一種手段掌挚,目標(biāo)在于擴(kuò)展類的功能,而非封裝數(shù)據(jù)菩咨。
2)而且重寫set和get方法需要把相似的代碼寫很多遍吠式,內(nèi)存管理容易出問題舅世。
3)通過屬性特質(zhì)修改了某個(gè)屬性的內(nèi)存管理語義,而此時(shí)還要記得要設(shè)置方法中也得修改設(shè)置關(guān)聯(lián)對象時(shí)所用的內(nèi)存管理語義奇徒。

第五章 引用計(jì)數(shù)

簡介:
一個(gè)對象所占的內(nèi)存在“解除分配”之后雏亚,只能放回“可用內(nèi)存池”。內(nèi)存不一定被復(fù)寫了摩钙。

autorelease

在方法返回的時(shí)候調(diào)用autorelease罢低。它會在稍后釋放對象,從而給調(diào)用者留下了足夠長的時(shí)間胖笛。保證對象跨越“方法調(diào)用邊界”后一定存活网持。

autorelease能延長對象生命期,使其跨越方法調(diào)用邊界后依然存活一段時(shí)間长踊。

ARC

優(yōu)點(diǎn):

1)增加程序效率功舀,比如一對release和retain會被抵消。
2)arc以后不用考慮set方法里面的“邊界情況”
3)arc會優(yōu)化處理返回aotorelease的情況身弊。

要點(diǎn):

  • ARC之后辟汰,可省去類中許多“樣板代碼”。
  • ARC機(jī)制:在合適的地方插入“保留”及“釋放”操作阱佛。
    變量的內(nèi)存管理語義可以通過修飾符指明帖汞。
  • ARC只負(fù)責(zé)管理OC對象的內(nèi)存。coreFoundation對象不歸ARC管理凑术,開發(fā)者應(yīng)調(diào)用CFRetain/CFRelease.
  • 由方法返回的對象翩蘸,其內(nèi)存管理語義總是通過方法名來體現(xiàn)。這是開發(fā)者必須遵守的規(guī)則淮逊。

塊會自動保留其捕獲的全部對象催首。

dealloc

注意:

1)雖說dealloc中釋放引用,但是開銷較大或系統(tǒng)內(nèi)稀缺的資源則不在此則泄鹏。像是文件描述符郎任、套接字、大塊內(nèi)存等命满。不能指望dealloc方法必定在某個(gè)特定的時(shí)機(jī)調(diào)用涝滴。
2)不要隨意在delloc里面調(diào)用方法。

要點(diǎn):

1)delloc里面應(yīng)該做的事情就是釋放對象胶台、KVO、通知等杂抽。不要做其他事情诈唬。
2)如果對象持有大量資源,那么應(yīng)該專門創(chuàng)建一個(gè)方法來釋放此資源缩麸,這樣的類要和使用者約定铸磅,用完資源后必須調(diào)用close方法。
3)異步執(zhí)行的方法不應(yīng)在delloc里調(diào)用,delloc最好不要調(diào)用方法阅仔,因?yàn)榇藭r(shí)對象已處于正在回收的狀態(tài)吹散。

異常處理

簡介:

@finally塊,無論是否拋出異常八酒,其中的代碼都會保證運(yùn)行空民,而且只運(yùn)行一次。
要點(diǎn):
1)捕獲異常時(shí)羞迷,一定要注意將try塊內(nèi)所創(chuàng)立的對象清理干凈界轩。
2)在默認(rèn)情況下,ARC不生成安全處理異常所需的清理代碼衔瓮。開始編譯器標(biāo)志后浊猾,可生成這種代碼,不過會導(dǎo)致程序變大热鞍,而且會降低運(yùn)行效率葫慎。關(guān)鍵字是-fobjc-arc-exceptions,在拋出異常的文件加上這個(gè)標(biāo)識。

保留環(huán)

weak修飾屬性特質(zhì)

自動釋放池

main里面的自動釋放池:理解成為最外圍捕獲全部自動釋放對象所用的池薇宠。

自動釋放池嵌套用的好處是:可以借此控制應(yīng)用程序的內(nèi)存峰值幅疼,使其不致過高。

應(yīng)用場景:

監(jiān)控內(nèi)存用量昼接,判斷其中有沒有需要解決的問題爽篷,如果沒完成這一步,就別急著優(yōu)化慢睡。雖然自動釋放池塊的開銷不太大逐工,但畢竟還是有的,所以盡量不要建立額外的自動釋放池漂辐。

要點(diǎn):

  • 自動釋放池排布在棧中泪喊,對象收到autorelease消息后,系統(tǒng)將其放入最頂端的池里髓涯。
  • 合理運(yùn)用自動釋放池袒啼,可降低應(yīng)用程序的內(nèi)存峰值。
  • @autoreleasepool這種新式寫法能創(chuàng)建出更為輕便的自動釋放池纬纪。

僵尸對象

簡介:

僵尸對象是調(diào)試內(nèi)存管理問題的最佳方式蚓再。

NSString和NSNumber的引用計(jì)數(shù)

NSString:OC對NSString有特殊照顧。所有的NSString的引用計(jì)數(shù)默認(rèn)初始值都會非常非常大包各。是一個(gè)常量摘仅。

NSNumber也類似,它使用了一種叫做“標(biāo)簽指針”的概念來標(biāo)注特定類型的數(shù)值问畅。

內(nèi)存區(qū)域

分為5個(gè)區(qū)域:

1)棧區(qū):由編譯器自動分配并釋放娃属,存放函數(shù)的參數(shù)值六荒,局部變量等。棧是系統(tǒng)數(shù)據(jù)結(jié)構(gòu)矾端,對應(yīng)線程/進(jìn)程是唯一的掏击。
優(yōu)點(diǎn):是快速高效
確定:數(shù)據(jù)不靈活
特點(diǎn):棧無需釋放,也就沒有釋放函數(shù)秩铆。
2)堆區(qū):需要程序員自己釋放
3)全局區(qū)(靜態(tài)區(qū)):全局變量和靜態(tài)變量的存儲是放在一起的砚亭,結(jié)束的時(shí)候由系統(tǒng)釋放。
全局區(qū)又分為:初始化的和未初始化的。
4)文字常量區(qū):存放常量字符串,程序結(jié)束后由系統(tǒng)釋放秕狰。
5)程序代碼區(qū):存放函數(shù)的二進(jìn)制代碼。

強(qiáng)大之處:
在聲明它的范圍里篓跛,所有變量都可以為其所捕獲。
但是捕獲的變量是不可以修改的坦刀,除非變量加上__block標(biāo)識愧沟。

捕獲:

如果塊所捕獲的變量是對象類型,那么就會自動保留它鲤遥。
如果通過讀取或?qū)懭氩僮鞑东@了實(shí)例變量沐寺,那么就會自動把self變量一起捕獲了,因?yàn)閷?shí)例變量與self所指代的實(shí)例關(guān)聯(lián)一起的盖奈。
塊拷貝的并不是對象本身混坞,而是指向這些對象的指針變量。

全局塊钢坦、棧塊及堆塊

全局塊:這種塊不會捕捉任何狀態(tài)(比如外圍的變量等)究孕,這種塊就相當(dāng)于是一個(gè)單例。
關(guān)鍵點(diǎn):
如果塊所捕獲的對象直接或者間接地保留了塊本身爹凹,那么就得當(dāng)心保留環(huán)問題厨诸。
一定要找個(gè)適當(dāng)?shù)臅r(shí)機(jī)解除保留環(huán),而不能把責(zé)任推給API的調(diào)用者禾酱。

框架

用C語言來實(shí)現(xiàn)API的好處是:可以繞過OC運(yùn)行期系統(tǒng)微酬,從而執(zhí)行速度。

多用派發(fā)隊(duì)列颤陶,少用同步鎖

原因:

若是在self對象上頻繁加鎖颗管,那么程序可能要等另一段與此無關(guān)的代碼執(zhí)行完畢,才能繼續(xù)執(zhí)行當(dāng)前代碼指郁,這么做其實(shí)并沒有必要忙上。

多個(gè)獲取方法可以并發(fā)執(zhí)行,而獲取方法和設(shè)置方法之間不能并發(fā)執(zhí)行闲坎。

柵欄:在隊(duì)列中疫粥,柵欄塊必須單獨(dú)執(zhí)行,不能與其他塊并行腰懂。并發(fā)隊(duì)列如果接下來處理的塊是個(gè)柵欄塊梗逮,那么就一直等當(dāng)前所有冰法快都執(zhí)行完畢,才會單獨(dú)執(zhí)行這個(gè)柵欄快绣溜。待柵欄塊執(zhí)行完畢以后慷彤,再按正常方法繼續(xù)向下處理。

要點(diǎn):

派發(fā)隊(duì)列可用來表述同步語義怖喻,這種做法要比使用@synchronized塊或NSLock對象更簡單底哗。
2)將同步和異步派發(fā)結(jié)合起來,可以實(shí)現(xiàn)與普通加鎖機(jī)制一樣的同步操作锚沸,而這么做卻不會阻塞執(zhí)行異步派發(fā)的線程跋选。
3)使用同步隊(duì)列及柵欄塊,可以令同步行為更加高效哗蜈。

NSCache勝過NSDictionary

原因:

1)NSCache,當(dāng)系統(tǒng)資源將要耗盡時(shí)前标,它可以自動刪減緩存。還會先行刪減“最永久未使用的對象距潘×读校”
2)NSCache是線程安全的。開發(fā)者在不編寫枷鎖代碼的前提下音比,多線程便可同時(shí)訪問NSCache俭尖。
3)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市洞翩,隨后出現(xiàn)的幾起案子稽犁,更是在濱河造成了極大的恐慌,老刑警劉巖菱农,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缭付,死亡現(xiàn)場離奇詭異,居然都是意外死亡循未,警方通過查閱死者的電腦和手機(jī)陷猫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來的妖,“玉大人绣檬,你說我怎么就攤上這事∩┧冢” “怎么了娇未?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長星虹。 經(jīng)常有香客問我零抬,道長,這世上最難降的妖魔是什么平夜? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮玩裙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吃溅。我一直安慰自己鸯檬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布京闰。 她就那樣靜靜地躺著颜及,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蹂楣。 梳的紋絲不亂的頭發(fā)上俏站,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音痊土,去河邊找鬼肄扎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛赁酝,可吹牛的內(nèi)容都是我干的犯祠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼酌呆,長吁一口氣:“原來是場噩夢啊……” “哼衡载!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起隙袁,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤痰娱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后菩收,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梨睁,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年娜饵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坡贺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遍坟。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡政鼠,死狀恐怖队魏,靈堂內(nèi)的尸體忽然破棺而出胡桨,到底是詐尸還是另有隱情,我是刑警寧澤刽虹,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布涌哲,位于F島的核電站阀圾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一谣妻、第九天 我趴在偏房一處隱蔽的房頂上張望减江。 院中可真熱鬧巡莹,春花似錦骂远、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽点弯。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工店归, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祭示,地道東北人谴古。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像毡代,于是被迫代替她去往敵國和親教寂。 傳聞我的和親對象是個(gè)殘疾皇子酪耕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容