序
這篇文章算是正正經(jīng)經(jīng)潛心下來開始重筑基礎(chǔ)储矩、探究底層的起點了,之前一直在找這樣或那樣的借口來逃避學(xué)習(xí)荠医,消遣生活吁脱,如今也著實被各種面試消遣了一個月桑涎,感慨良多〖婀保總而言之還是希望能通過一些文字攻冷,幫助自己和看這篇文章的朋友,理解知識遍希,從而記住知識等曼,到最后形成知識體系,“牽一發(fā)孵班,思全身”涉兽。也借此幫助自己整理思路,搭建屬于自己的知識體系篙程。
第1章 自動引用計數(shù)
1.1 什么是自動引用計數(shù)
- 自動引用計數(shù)(ARC - Automatic Reference Counting)是指在內(nèi)存管理中 對引用 采用自動計數(shù)的技術(shù)枷畏。
- 時間軸:2012年 - iOS 5 - Xcode 4.2
https://developer.apple.com/download/more/
1.2 內(nèi)存管理/引用計數(shù)
1.2.1 概述
- 辦公室開關(guān)燈的例子可以很好的描述引用計數(shù)對于內(nèi)存的管理。
- 白天上班人多肯定多開燈虱饿,晚上一兩個人加班也就開一兩盞燈拥诡,下班了關(guān)燈鎖門。
1.2.2 內(nèi)存管理的思考方式
- 誰生成誰持有氮发,誰引用誰釋放渴肉,沒引用就別想插手別人的人生了(非自己持有的對象無法釋放)。
- 對象操作與Objective - C方法的對應(yīng)
- Cocoa框架中Foundation框架類庫的NSObject類擔(dān)負(fù)內(nèi)存管理的職責(zé)爽冕。alloc/retain/release/dealloc方法也都指代的是NSObject中對應(yīng)的實例方法仇祭。
1.2.2.1 生成/持有/銷毀
這一節(jié)嘗試代碼操作,首先要介紹兩個點颈畸,一個是ARC和MRC的切換乌奇,還有一個是ARC機制下如何觀察對象的引用計數(shù)(retainCount)。
ARC和MRC切換方法一:單一文件切換
選擇項目中的Target-> Build Phases-> Complie Sources中選擇需要ARC/MRC的文件雙擊眯娱, ARC在輸入框中輸入:-fobjc-arc礁苗,如果不要ARC則輸入:-fno-objc-arc
ARC和MRC切換方法二:切換MRC環(huán)境
選擇項目中的Target -> Build Sttings -> All -> 搜索‘a(chǎn)utomatic’ -> 把 Objective-C Automatic Reference Counting 設(shè)置為 NO
- ARC機制下如何觀察對象的引用計數(shù)(retainCount)
printf("retain count = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj)));'
這里實際上就是將OC對象轉(zhuǎn)換為CF對象并查看其引用計數(shù),注意這里用的是__bridge徙缴,而不是__bridge_retain试伙。
關(guān)于對象與指針
- 正文開始前還需要說點基礎(chǔ)性的東西,這關(guān)系到后面生成/持有的理解問題于样。
- 我們來看這行代碼:
UIView * view = [[UIView alloc] init];
代碼很簡單疏叨,實例化了一個UIView對象,那么誰是對象穿剖?如果你認(rèn)為imgView是對象那就錯了蚤蔓,view是指針,指針指向的是對象携御。- 這行代碼實際上產(chǎn)生的是兩個東西:UIView變量 和 UIView對象昌粤,UIView對象存儲于內(nèi)存,UIView變量指向內(nèi)存中的對象啄刹。
- 本質(zhì)上來說涮坐,類是一種指針類型的變量,程序中定義的UIImageView* 類型只是存放一個地址值誓军,保存在main()函數(shù)的動態(tài)存儲區(qū)袱讹,它指向?qū)嶋H的UIView對象,而真正的UIView對象則存放堆(heap)內(nèi)存中昵时。
- 所有對象都只能通過指針變量來訪問捷雕,堆內(nèi)存中也可以有多個指針,也就是允許多個指針指向同一個對象壹甥,例如:
UIImageView * imgView_other = [[UIImageView alloc] init];
- 如果堆內(nèi)存中的對象沒有任何變量指向該對象救巷,那么程序就無法訪問該對象句柠,就要釋放內(nèi)存浦译,否則就造成內(nèi)存泄漏。
自己生成的對象溯职,自己所持有
- 使用alloc/new/copy/mutableCopy名稱開頭的方法名意味著自己生成的對象只有自己持有精盅。
- 我們來敲代碼試試看:
id obj = [[NSObject alloc] init];
printf("retainCount = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj)));
輸出結(jié)果:retainCount = 1
- 使用NSObject類的alloc類方法就能自己生成并持有對象。指向生成并持有對象的指針被賦值給obj谜酒。實際上這就是我上面為什么要談到的對象與指針的概念叹俏,obj是個指針。別著急僻族,下面還有問題粘驰。
- copy方法和mutableCopy方法這里就不多贅述了,都是生成并持有對象的副本鹰贵,區(qū)別在于對象的可變和不可變晴氨。
非自己生成的對象,自己也能持有
- 用alloc/new/copy/mutableCopy以外的方法獲得對象碉输,因為不是自己生成并持有籽前,所以自己不是對象的持有者。
- 同樣敷钾,敲代碼看看:
id obj = [NSMutableArray array];
printf("retainCount = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj)));
輸出結(jié)果:retainCount = 1
- 源代碼中枝哄,NSMutableArray類對象被賦給obj,但變量obj自己并不持有該對象阻荒。使用retain方法可以持有對象挠锥。好的,那么問題來了侨赡,為什么obj并沒有持有對象蓖租,打印obj的retainCount粱侣,結(jié)果依然是1?
這就是上文提及對象與指針的意義蓖宦,obj其本身是個指針齐婴,指向內(nèi)存中的對象,這里打印的retainCount其實質(zhì)是對象的retainCount稠茂,賦值給obj的是未持有對象的指針柠偶。如果想要obj持有對象,就需要:
[obj retain];
printf("retainCount = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj)));
輸出結(jié)果:retainCount = 2
所以這里一定要搞明白睬关,其實這里還可以再探究下array這個類方法诱担,回頭有時間再填這個坑吧。
在不需要的時候电爹,將自己持有的對象釋放
- 這塊原題是“不再需要自己持有的對象時釋放”蔫仙,讀起來理解起來實在拗口,改一下丐箩。自己持有的對象匀哄,一旦不再需要,持有者有義務(wù)釋放該對象雏蛮,使用release方法涎嚼。
- 同樣,敲代碼:
id obj = [NSMutableArray array];
[obj retain];
printf("retainCount = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj)));
[obj release];
printf("retainCount = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj)));
輸出結(jié)果:
retainCount = 2
retainCount = 1