Objective-C學(xué)習(xí)筆記Cocoa生命周期
Objective-C學(xué)習(xí)筆記Cocoa生命周期是本文要介紹的內(nèi)容,主要是來學(xué)習(xí)Cocoa中對象的生命周期,對象的生命周期包括誕生(通過alloc或new方法實現(xiàn))、生存(接收消息和執(zhí)行操作)、交友(借助方法的組合和參數(shù))、釋放(當(dāng)它們的生命結(jié)束時最終死去)。當(dāng)對象的生命周期結(jié)束時,它們的原材料(內(nèi)存)將被回收以供新的對象使用。
1、引用計數(shù)(reference counting):
每個對象有一個與之相關(guān)聯(lián)的整數(shù),稱做它的引用計數(shù)器或保留計數(shù)器。當(dāng)某段代碼需要訪問一個對象時,該代碼將該對象的保留計數(shù)器值加1,表示“我要訪問該對象”。當(dāng)這段代碼結(jié)束對象訪問時,將對象的保留計數(shù)器值減1,表示它不再訪問該對象。當(dāng)保留計數(shù)器值為0時,表示不再有代碼訪問該對象了,因此對象將被銷毀,其占用的內(nèi)存被系統(tǒng)回收以便重用。
當(dāng)使用alloc、new或copy(生成接收對象的一個副本)創(chuàng)建一個對象時,對象的保留計數(shù)器值被設(shè)置成1.要增加對象的保留計數(shù)器值,可以給對象發(fā)送一條retain消息,要減少對象的保留計數(shù)器值,可以給對象發(fā)送一條release消息。
當(dāng)一個對象因其保留計數(shù)器歸0而將被銷毀時,Objective-C自動向?qū)ο蟀l(fā)送一條dealloc消息。你可以在自己的對象中重寫dealloc方法。可以通過這種方式釋放已經(jīng)分配的全部相關(guān)資源。一定不要直接調(diào)用dealloc方法。要獲得保留計數(shù)器的當(dāng)前值,可以發(fā)送retainCount消息。簽名如下:
- - (id) retain;
- //申請- (void) release;
- //釋放- (unsigned) retainCount;
- //當(dāng)前計數(shù)器值
- 例如:[[car retain] setTire: tire atIndex:2]; 表示要求car對象將其保留計數(shù)器值加1并執(zhí)行setTire操作。Example:
- //
- // Main.m
- // RetainCount1
- // 內(nèi)存管理練習(xí)1
- //
- // Created by Elf Sundae on 10/23/10.
- // Copyright 2010 Elf.Sundae(at)Gmail.com. All rights reserved.
- //
- #import <Cocoa/Cocoa.h>
- @interface RetainTracker : NSObject
- @end15
- @implementation RetainTracker
- - (id) init
- {
- if (self = [super init])
- {
- NSLog(@"init: Retain count of %d.",[self retainCount]);
- }
- return self;25 }
- - (void) dealloc28 {
- NSLog(@"dealloc called.Bye Bye.");
- [super dealloc];31 }
- @end
- int main (int argc, const char * argv[])
- {
- RetainTracker *tracker = [RetainTracker new];
- [tracker retain];
- NSLog(@"%d",[tracker retainCount]);
- [tracker retain];
- NSLog(@"%d",[tracker retainCount]);
- [tracker release];
- NSLog(@"%d",[tracker retainCount]);
- [tracker release];
- NSLog(@"%d",[tracker retainCount]);
- [tracker retain];
- NSLog(@"%d",[tracker retainCount]);
- [tracker release];
- NSLog(@"%d",[tracker retainCount]);
- [tracker release];
- return 0;66 }
輸出:
- init: Retain count of 1.
- dealloc called.Bye Bye.
2、對象所有權(quán)(object ownership):
如果一個對象具有指向其他對象的實例變量,則稱該對象擁有這些對象。這意味著該實體要負(fù)責(zé)確保對其擁有的對象進行清理。
當(dāng)多個實體擁有某個特定對象時,對象的所有權(quán)關(guān)系就更復(fù)雜了,這也是保留計數(shù)器值可能大于1的原因。在上面的RetainCount1例子中,main()函數(shù)擁有RetainTracker類的對象,因此main()要負(fù)責(zé)清理該類的對象。
回憶一下在OOP基礎(chǔ)章節(jié)里Car的engine setter方法:
- - (void) setEngine: (Engine *) newEngine;
以及如何在main()函數(shù)中調(diào)用該方法:
- Engine *engine = [Engine new];[car setEngine: engine];
現(xiàn)在哪個實體擁有engine對象?是main()函數(shù)還是Car類?
下面是編寫setEngine的一種更好的方法:
- - (void) setEngine: (Engine *) newEngine
- {
- [newEngine retain];
- [engine release];
- engine = newEngine;
- } // setEngine
在訪問方法中,如果先保留新對象,然后再釋放舊對象,這不會出問題。
- In your accessors, if you retain the new object before you release the old object, you’ll be safe.
3、自動釋放(Autorelease)
自動釋放池(autorelease pool),它是一個存放實體的池(集合),這些實體可能是對象,能夠被自動釋放。
NSObject類提供了一個autorelease方法:
- - (id) autorelease;
該方法預(yù)先設(shè)定了一條在將來某個時間發(fā)送的release消息,其返回值是接收消息的對象。當(dāng)給一個對象發(fā)送autorelease消息時,實際上是將該對象添加到NSAutoreleasePool中。當(dāng)自動釋放池被銷毀時,會向該池中的所有對象發(fā)送release消息。
- - (NSString *) description
- {
- NSString *description;
- description = [[NSString alloc]
- initWithFormat: @"I am %d years old", 4];
- return ([description autorelease]);7} // description
自動釋放池的銷毀時間:
在使用Foundation庫工具中,創(chuàng)建和銷毀自動釋放池的方法非常明確:
- NSAutoreleasePool *pool;pool = [[NSAutoreleasePool alloc] init];…[pool release];
創(chuàng)建一個自動釋放池時,該池自動成為活動的池。釋放該池時,其保留計數(shù)器值歸0,然后該池被銷毀。在銷毀過程中,該池釋放其包含的所有對象。
當(dāng)時用AppKit時,Cocoa定期自動為你創(chuàng)建和銷毀自動釋放池。通常是在程序處理完當(dāng)前事件(如鼠標(biāo)單擊或按鍵)以后執(zhí)行這些操作。你可以使用任意多的自動釋放對象,當(dāng)不再使用它們時,自動釋放池將自動為你清理這些對象。
說明:在Xcode自動生成的代碼中使用了另一種銷毀自動釋放池中對象的方式:-drain方法,該方法只是清空自動釋放池而不銷毀它。-drain方法只適用于Mac OS X 10.4(Tiger)及更高版本。
自動釋放池的工作過程:示例:RetainCount2
- OBJECTIVE-C CODE :RetainCount2
- //
- // Main.m
- // RetainCount2
- // 內(nèi)存管理練習(xí)2: 使用自動釋放池
- //
- // Created by Elf Sundae on 10/25/10.
- // Copyright 2010 Elf.Sundae(at)Gmail.com. All rights reserved.
- //
- #import <Cocoa/Cocoa.h>
- @interface RetainTracker : NSObject
- @end
- @implementation RetainTracker
- - (id) init
- {
- if (self = [super init])
- {
- NSLog(@"init: Retain count of %d.",[self retainCount]);
- }
- return self;
- }
- - (void) dealloc
- {
- NSLog(@"dealloc called.Bye Bye.");
- [super dealloc];
- }
- @end
- int main (int argc, const char * argv[])
- {
- // 創(chuàng)建一個自動釋放池
- NSAutoreleasePool *pool;
- pool = [[NSAutoreleasePool alloc] init];
- // 創(chuàng)建(new)一個RetainTracket對象
- RetainTracker *tracker = [RetainTracker new]; // count:1
- NSLog(@"%d",[tracker retainCount]);
- // 處于演示目的,retain一個trancker
- [tracker retain]; // count:2
- NSLog(@"%d",[tracker retainCount]);
- // 向?qū)ο蟀l(fā)送autorelease消息,將該對象添加到自動釋放池pool中
- [tracker autorelease]; // count: still 2
- NSLog(@"%d",[tracker retainCount]);
- // release該對象以抵消上面的 retain
- [tracker release]; //count: 1
- NSLog(@"%d",[tracker retainCount]);
- NSLog(@"releaseing pool");
- [pool release];
- return 0;
- }
小結(jié):Objective-C學(xué)習(xí)筆記Cocoa生命周期的內(nèi)容介紹完了,希望通過本文的學(xué)習(xí)能對你有所幫助!