Objective-c自學筆記(5)-自動釋放池

來源:互聯網
上載者:User
解決的問題


每一個東西的產生都是在實際生活迫切需要這樣的東西後,人們通過思考發明創造某些東西用以解決這個問題。那麼自動釋放池用來解決什麼問題。請看下面的例子:


對於一些有傳回值的訊息(方法),它返回的對象要交給誰來釋放其記憶體,比如NSObject類中description訊息


-(NSString*)description{    NSString *description;    description = [[NSString alloc]initWithFormat:@"hello world"];    return (description);    }//description

這個時候description字串的記憶體釋放要交給誰。肯定不應該在description方法裡面,這樣的話,返回的對象指向的就是一個被釋放的記憶體了。這肯定是不可行的。

那麼如果讓調用者來釋放呢,那麼就得像下面這樣寫:


RetainTracker *tracker = [RetainTracker new];    NSString *desc = [tracker description];    [desc release];

那麼這樣寫有什麼問題麼。沒什麼問題,就是多了一行代碼。有什麼更好的方法,能唯寫一行代碼就能達到自動釋放的效果。既然有這個需求,那麼肯定會有人試著去解決這個問題。


解決方案


蘋果公司在Cocoa架構中有一個自動釋放池的概念,在NSObject類中提供了一個叫做autorelease的方法。


-(id)autorelease{};//autorelease

該方法預先設定了一條會在未來某個時間發送的release訊息, 返回的id代表接受這條訊息的對象。當我們調用該對象的autorelease方法的時候,實際上是把該對象放到自動釋放池,當自動釋放池被銷毀時,會向該池中的所有對象發送release訊息。這個時候我們把description 方法修改成如下形式:


-(NSString*)description{    NSString *description;    description = [[NSString alloc]initWithFormat:@"hello world"];    return ([description autorelease]);    }//description

這個時候我們在調用的地方只需要一句話就做了記憶體釋放的工作。不用在單獨添加調用release方法的語句。


建立


我們上面說了那麼多,都在說自動釋放池可以幫我們解決掉對象自動釋放的問題,但是這個自動釋放池也不是自己就存在的,它需要我們自己來顯示的建立。可以通過2種方式來建立自動釋放池。


通過@autoreleasepool關鍵字


當你使用@autoreleasepool{}時,所有在花括弧裡的代碼都會被放入這個池子中。但是任何在該花括弧的變數都無法在括弧外使用。


通過NSAutoreleasePool對象


該對象需要建立,在該對象建立語句和銷毀語句的代碼都相當於放入了自動釋放池中。


NSAutoreleasePool *pool;    pool = [NSAutoreleasePool new];    RetainTracker *tracker = [RetainTracker new];    NSString *desc = [tracker description];    [desc release];    // count: 1    [tracker retain]; // count: 2    NSLog (@"%d", [tracker retainCount]);    [tracker retain]; // count: 3    NSLog (@"%d", [tracker retainCount]);    [tracker release]; // count: 2    NSLog (@"%d", [tracker retainCount]);    [tracker release]; // count: 1    NSLog (@"%d", [tracker retainCount]);    [tracker retain]; // count 2    NSLog (@"%d", [tracker retainCount]);    [tracker release]; // count 1    NSLog (@"%d", [tracker retainCount]);    [tracker release]; // count: 0, dealloc it    [pool release];

上面的代碼就是一個自動釋放池建立過程。


推薦


優先使用@autoreleasepool{}關鍵字的方式來建立自動釋放池。


工作原理


那麼自動釋放池的工作原理到底是什麼。下面用一個例子來講解一下。


#import <Foundation/Foundation.h>@interface RetainTracker : NSObject@end // RetainTracker@implementation RetainTracker- (id) init{if (self = [super init]) {NSLog (@"init: Retain count of %d.",   [self retainCount]);}return (self);} // init- (void) dealloc{NSLog (@"dealloc called. Bye Bye.");[super dealloc];} // dealloc@end // RetainTrackerint main (int argc, const char * argv[]){    NSAutoreleasePool *pool;    pool = [[NSAutoreleasePool alloc] init];    RetainTracker *tracker;    tracker = [RetainTracker new]; // count: 1    [tracker retain]; // count: 2    [tracker autorelease]; // count: still 2    [tracker release]; // count: 1    NSLog (@"releasing pool");    [pool release];     // gets nuked, sends release to tracker    @autoreleasepool    {        RetainTracker *tracker2;        tracker2 = [RetainTracker new]; // count: 1                [tracker2 retain]; // count: 2        [tracker2 autorelease]; // count: still 2        [tracker2 release]; // count: 1                NSLog (@"auto releasing pool");    }        return (0);}

第一個代碼塊是使用NSAutoreleasePool對象建立的自動釋放池。和之前的語句相比,多了一個[tracker autorelease]語句,該語句做了啥。它並沒有給引用計數器的值做操作,而是把該對象添加到自動釋放池中,在自動釋放池中也有一個引用指向了該對象。當自動釋放池銷毀時,會向改對象發送一條release訊息。由於我們先向tracker對象發送了retain對象,計數器加1,然後發送release訊息,計數器減1,但是此時tracker對象的dealloc方法並不會調用,因為new方法讓計數器加1,所以pool對象的release方法沒調用之前,tracker對象的計數器的值為1,當pool對象的調用release後,自動釋放池的計數器為0,此時pool對象的dealloc方法會被調用,然後會想池中的對象發送release對象,那麼此時tracker對象的計數器值會變為0,tracker對象的dealloc方法被調用,所以輸出應該如下:


2015-02-01 00:12:02.426 09.02 RetainCount-2[860:58571] init: Retain count of 1.2015-02-01 00:12:02.428 09.02 RetainCount-2[860:58571] releasing pool2015-02-01 00:12:02.428 09.02 RetainCount-2[860:58571] dealloc called. Bye Bye.

另外一個@autoreleasepool關鍵字建立的自動釋放池也是一樣的過程。整個輸出如下:


2015-02-01 00:18:23.932 09.02 RetainCount-2[876:61410] init: Retain count of 1.2015-02-01 00:18:23.933 09.02 RetainCount-2[876:61410] releasing pool2015-02-01 00:18:23.934 09.02 RetainCount-2[876:61410] dealloc called. Bye Bye.2015-02-01 00:18:23.934 09.02 RetainCount-2[876:61410] init: Retain count of 1.2015-02-01 00:18:23.934 09.02 RetainCount-2[876:61410] auto releasing pool2015-02-01 00:18:23.934 09.02 RetainCount-2[876:61410] dealloc called. Bye Bye.Program ended with exit code: 0


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.