Retain Count
繼上一篇文章所述,Retain Count 是我們管理 Objective-C 程式記憶體使用最重要的一環。但是我們不難發現,其實如果真的所有的東西都必須經過 alloc、init、retain、release 的動作,會讓整篇程式上上下下充斥著這些程式碼,反而降低了整個程式的閱讀性、也提高了出錯的危險。這裡,Auto Release Pool 這個設計就出現了。從字面上看來,它可以自動的幫我們釋放掉記憶體,但其實它並沒有像是垃圾回收那樣複雜的演算法存在。它其實是一個聰明、卻又單純、簡單的設計,並且解決上面所述造成程式碼撰寫的複雜度、並且同時提高程式在編成的時候的彈性。
我們想像記憶體的空間是個游泳池,而建立的物件實體就像是游泳池的遊客。遊客在游泳池開門之後開始戲水,當游泳池要打烊的時候,遊客就會離開。
這個想法運用在這邊就是,我們先建立一個 NSAutoreleasePool 的物件。之後,我們只要在所有自己建立的物件實體,呼叫方法 -(void)autorelease,便可以讓該物件與 AutoreleasePool 做連結。Pool 也不做什麼複雜計算、搜尋,只是單純的把該物件實體記錄下來。當 Pool 被 Release 掉的時候,Pool 便將所有跟他連結在一起的物件,全部個別的呼叫「一次」-(void)release。如此一來,該物件就不需要擔心,什麼時候該釋放它,Pool 會幫我們管好一切。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OBJ *o1 = [[[OBJ alloc] init] autorelease];
OBJ *o2 = [[[OBJ alloc] init] autorelease];
// Do Something
[pool release];
這個機制最重要的運用是,由於所有的 Cocoa 應用程式都至少會建立一個 Autorelease Pool。我們可以開始取得一些「暫時物件」的實體,並且讓系統在適當的時候,自己釋放掉那些暫時物件。最好的例子莫過於字串。我們可以用以下的程式碼取得一個字串物件的實體:
NSString *str = @"Some Text Message";
NSString *str2 = [NSString stringWithFormat:@"Number: %d", 50];
上面兩種取得字串的方式,便是包含了 Auto Release 機制在的。
由於系統本身已經預先建立好一個 Autorelease Pool,所以當後者 @"Some Text Message"; 被使用的時候,系統便會使用 alloc->init->autorelease 一連串的方法建立一個物件實體,並且把實體的位置回傳。我們不需要額外的程式碼便可以得到想要的物件。這個原則在物件、實體方法 (methods) 回傳值的時候非常的有用。使用者使用你所設計的方法取得的實體並不需要在多花時間去考慮是否要 release。
但是,這時又會產生一個疑問:相同的都是取得實體,我該怎麼知道哪些是需要 release,哪些不需要?沒錯,這確實是一件很重要的事情。因為當一個物件實體的 Retain Count 降為 0 之後,它就會呼叫 dealloc,並且摧毀。從此之後,如果又有人(不論是你自己,還是 Autorelease Pool)呼叫了實體方法 release,便會因為實體根本不存在而導至崩潰。
要知道究竟是哪一個物件需要手動 release,我們只需要掌握一條原則:所有權在你自己身上的,你自己釋放,其餘的交給 Autorelease Pool。什麼樣的實體,所有權會在自己身上?很簡單。你取得實體的方法,具有幾個關鍵字:init、retain、copy。只要是其中一項,你便具有該物件的所有權,你就得要自己手動 release。
清楚了嗎?
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言