9.1前言
記憶體管理在objective-C 2.0中是非常重要的,記憶體管理做得好不好,最直觀的就是反應在你的程式crash上面。想要你的程式健壯穩定,那麼請務必搞明白記憶體管理。
9.2 objective-C 2.0是怎樣一個記憶體機制?
在objective-C 2.0語言中,記憶體管理主要是基於一個 release count的值來進行判斷系統是否要回收該記憶體。當某對象的 retain count等於0時,系統則會回收這段記憶體。所以當我們想要釋放掉某項目時,我們只需要使其retain count等於0即可。當我們想要hold住該段記憶體以便後面繼續使用(具體怎麼用將會在後面提到)那麼你只需要保證在你要使用它之前 它的retain count>0即可。為何蘋果要這樣做?等下告訴你。
首先還是說明 retain count是如何去操作的。假設我們有一個class A:NSObject,然後我們聲明一個變數 A *a,不用在意它是臨時變數還是類屬性變數,這時候它的retain count等於0;當我們給這個變數建立記憶體空間的時候 我們會使用NSObject類的 alloc 函數:a=[A alloc];這時候 a的retain count則會+1,能使 retain count +1的函數不止有alloc,還有 [a retain],和[a copy],關於這兩個函數會在什麼時候使用以及他們的區別,將在後面討論。要想使retain count -1 你需要調用函數 [a release];那麼寫一串代碼來直觀的表示retain count的變化:
#import "A.h"
/** 略**/
-(void) retainCountDemo
{
A *a; //retain count of a is 0 a = [A alloc]; //retain count of a is 1
[a retain]; //retain count of a is 2
[a release]; //retain count of a is 1
A* a1 = [a copy]; //retain count of a1 is 1,and a's is 1 too
[a release]; //retain count of a is 0, and it will be dealloced
[a1 release]; //retain count of a1 is 0, and it will be dealloced
return;
}
9.3 copy 和 retain的區別?
copy和retain的區別在於它們的字面意思,不同之處在於一個是直接引用(比如說對象的引用),然後retain count+1,另外一個是複製使用(比如說字串的使用),將複製到的對象a1的retain count+1.
9.4 他們有什麼用?
objective-C 2.0是一門物件導向的語言,通過使用 retain count來就可以讓開發人員在各自的模組中建立使用以後就“釋放”,而不用擔心影響到其他模組如果同時會使用到該變數而造成的crash。最典型也是最常用的就是我們的NSURLConnection類裡面的request,這種非同步請求,你並不知道什麼時候該釋放,因為你沒法判斷什麼時候請求能夠返回,所以通過使用retain count 你只關心你建立了一個 NSURLConnction,在設定完接收對象,發送完請求以後你就可以release掉它了,而無需關心記憶體泄露之類的問題。因為在發送請求的時候,NSURLConnction會將自己retain一次,這時候的retain count變為2,你在自己的函數中調用release的時候retaincount則變為1,而當該請求返回的時候,完成回呼函數,會自動調用release一次,這時候NSURLConnction的retain count變為0而釋放掉。
通過上面的例子來總結,我們可以發現,其實這是一種延遲釋放的機制(好吧,這個詞是我自己想到的)。依照這個我們可以解決很多個物件共用而不知道該誰去管理記憶體的問題,蘋果的做法就是:管好你自己,你自己alloc+retain多少次,那麼請你release多少次。所以,記憶體管理最基本的就是管好你自己!
9.5 記憶體管理有沒有更簡單點的方法呢?
有!但是不建議使用。
方法1:autorelease函數,通過函數名你應該可以知道這個是幫你自動release的。但是需要注意的是這個函數只會自動幫你release1次,你如果在中間使用了retain之類的,所以還請手動release。同時這個有一個致命的缺點,你想用autorelease在class A中建立對象然後傳遞給class B使用的話這是非常危險的,autorelease是基於系統內建的自動釋放池來進行記憶體管理,系統會每隔一段時間去檢測施放池中的對象,並且釋放不在使用的對象。當你傳遞給B的時候,還沒來得及使用,被自動釋放掉了,那麼你的程式又會crash。所以 autorelease通常都是在局部對象中使用。
方法2:IOS 5 ARC(Automatic Reference Counting),蘋果終於發現了做IOS開發有太多無證程式猿了,經常因為記憶體釋放不好而導致野指標,記憶體泄露,各種問題的存在。所以蘋果在IOS5的SDK中加了這麼一個東西,自動引用計數器。好了,這下各位可以放心的使用,而不用麻煩的去數retain release了。如果你能保證你的客戶都會乖乖升級到IOS5的話…… 顯然,暫時這東西還不太靠譜……
9.6 稍微進階點的應用:
於是我就只想到一個大量產生的臨時對象和自動釋放池這兩個名詞,具體如何使用,請去查閱蘋果API,keywords:NSAutoreleasePool。
9.7 後記:
上面所寫都是我自己對Objective-C的理解和自己以前所犯錯誤而總結出來的經驗,遺憾的是正好我高考語文考試不及格,所以寫的文章也不太好懂,還請見諒,如果有什麼疑問或者意見,還請指出一起討論學習。執行個體代碼,非常簡單,如果有朋友看了也不太明白,還請自己寫demo驗證。對於委託(delegate),通知(notification),屬性等這些東西本來是想也在這裡說一說的,但是因為思維跳躍比較大,所以還是抽時間另外寫出來。