5.21日音訊,objective-C-引用計(jì)數(shù)詳解。obj-c本質(zhì)就是"改進(jìn)過(guò)的c語(yǔ)言",大家都知道c語(yǔ)言是沒(méi)有垃圾回收(GC)機(jī)制的(注:雖然obj-c2.0后來(lái)增加了GC功能,但是在iphone上不能用,因此對(duì)于iOS平臺(tái)的程序員來(lái)講,這個(gè)幾乎沒(méi)啥用),所以在obj-c中寫(xiě)程序時(shí),對(duì)于資源的釋放得由開(kāi)發(fā)人員手動(dòng)處理,相對(duì)要費(fèi)心一些。
引用計(jì)數(shù)
這是一種古老但有效的內(nèi)存管理方式。每個(gè)對(duì)象(特指:類的實(shí)例)內(nèi)部都有一個(gè)retainCount的引用計(jì)數(shù),對(duì)象剛被創(chuàng)建時(shí),retainCount為1,可以手動(dòng)調(diào)用retain方法使retainCount+1,同樣也可以手動(dòng)調(diào)用release方法使retainCount-1,調(diào)用release方法時(shí),如果retainCount值減到0,系統(tǒng)將自動(dòng)調(diào)用對(duì)象的dealloc方法(類似于c#中的dispose方法),開(kāi)發(fā)人員可以在dealloc中釋放或清理資源。
1、基本用法
為了演示這種基本方式,先定義一個(gè)類Sample
類接口部分Sample.h
//
//Sample.h
//MemoryManage_1
//
//Createdbyjimmy.yangon11-2-19.
//Copyright2011__MyCompanyName__.Allrightsreserved.
//
#import<Foundation/Foundation.h>
@interfaceSample:NSObject{
}
@end
類實(shí)現(xiàn)部分Sample.m
//
//Sample.m
//MemoryManage_1
//
//Createdbyjimmy.yangon11-2-19.
//Copyright2011__MyCompanyName__.Allrightsreserved.
//
#import"Sample.h"
@implementationSample
-(id)init
{
if(self=[superinit]){
NSLog(@"構(gòu)造函數(shù)被調(diào)用了!當(dāng)前引用計(jì)數(shù):%d",[selfretainCount]);
}
return(self);
}
-(void)dealloc{
NSLog(@"析構(gòu)函數(shù)將要執(zhí)行...,當(dāng)前引用計(jì)數(shù):%d",[selfretainCount]);
[superdealloc];
}
@end
代碼很簡(jiǎn)單,除了"構(gòu)造函數(shù)"跟"析構(gòu)函數(shù)"之外,沒(méi)有任何其它多余處理。
主程序調(diào)用
#import<Foundation/Foundation.h>
#import"Sample.h"
intmain(intargc,constchar*argv[]){
Sample*_sample=[Samplenew];//構(gòu)造函數(shù)被調(diào)用了!當(dāng)前引用計(jì)數(shù):1
NSLog(@"_sample.retainCount=%d",[_sampleretainCount]);//1
[_sampleretain];
NSLog(@"_sample.retainCount=%d",[_sampleretainCount]);//2
[_sampleretain];
NSLog(@"_sample.retainCount=%d",[_sampleretainCount]);//3
[_samplerelease];
NSLog(@"_sample.retainCount=%d",[_sampleretainCount]);//2
[_samplerelease];
NSLog(@"_sample.retainCount=%d",[_sampleretainCount]);//1
[_samplerelease];//析構(gòu)函數(shù)將要執(zhí)行...,當(dāng)前引用計(jì)數(shù):1
NSLog(@"_sample.retainCount=%d",[_sampleretainCount]);//1,注:即便是在析構(gòu)函數(shù)執(zhí)行后,如果立即再次引用對(duì)象的retainCount,仍然返回1,但以后不管再試圖引用該對(duì)象的任何屬性或方法,都將報(bào)錯(cuò)
NSLog(@"_sample.retainCount=%d",[_sampleretainCount]);//對(duì)象被釋放之后,如果再嘗試引用該對(duì)象的任何其它方法,則報(bào)錯(cuò)
//[_sampleretain];//同上,會(huì)報(bào)錯(cuò)
return0;
}
這段代碼主要驗(yàn)證:對(duì)象剛創(chuàng)建時(shí)retainCount是否為1,以及retain和release是否可以改變r(jià)etainCount的值,同時(shí)retainCount減到0時(shí),是否會(huì)自動(dòng)執(zhí)行dealloc函數(shù)
nil的問(wèn)題:
1.1如果僅聲明一個(gè)Sample類型的變量(其實(shí)就是一個(gè)指針),而不實(shí)例化,其初始值為nil
1.2變量實(shí)例化以后,就算release掉,dealloc被成功調(diào)用,其retainCount并不馬上回到0(還能立即調(diào)用一次且僅一次[xxxretainCount]),而且指針變量本身也不會(huì)自動(dòng)歸為nil值
1.3dealloc被調(diào)用后,必須手動(dòng)賦值nil,retainCount才會(huì)自動(dòng)歸0
以上結(jié)論是實(shí)際試驗(yàn)得出來(lái)的,見(jiàn)下面的代碼:
Sample*s;
NSLog(@"s%@,retainCount=%d",s==nil?@"isnil":@"isnotnil",[sretainCount]);//sisnil,retainCount=0
s=[Samplenew];
NSLog(@"s%@,retainCount=%d",s==nil?@"isnil":@"isnotnil",[sretainCount]);//sisnotnil,retainCount=1
[srelease];
NSLog(@"s%@,retainCount=%d",s==nil?@"isnil":@"isnotnil",[sretainCount]);//sisnotnil,retainCount=1
//NSLog(@"s%@,retainCount=%d",s==nil?@"isnil":@"isnotnil",[sretainCount]);//報(bào)錯(cuò):Programreceivedsignal:“EXC_BAD_ACCESS”.
s=nil;
NSLog(@"s%@,retainCount=%d",s==nil?@"isnil":@"isnotnil",[sretainCount]);//sisnil,retainCount=0
所以千萬(wàn)別用if(x==nil)或if([xretainCount]==0)來(lái)判斷對(duì)象是否被銷毀,除非你每次銷毀對(duì)象后,手動(dòng)顯式將其賦值為nil
2、復(fù)雜情況
上面的示例過(guò)于簡(jiǎn)章,只有一個(gè)類自己獨(dú)耍,如果有多個(gè)類,且相互之間有聯(lián)系時(shí),情況要復(fù)雜一些。下面我們?cè)O(shè)計(jì)二個(gè)類Shoe和Man(即“鞋子類”和”人“),每個(gè)人都要穿鞋,所以Man與Shoe之間應(yīng)該是Man擁有Shoe的關(guān)系。
Shoe.h接口定義部分
#import<Foundation/Foundation.h>
@interfaceShoe:NSObject{
NSString*_shoeColor;
int_shoeSize;
}
//鞋子尺寸
-(void)setSize:(int)size;
-(int)Size;
//鞋子顏色
-(void)setColor:(NSString*)color;
-(NSString*)Color;
//設(shè)置鞋子的顏色和尺碼
-(void)setColorAndSize:(NSString*)pColorshoeSize:(int)pSize;
@end
Shoe.m實(shí)現(xiàn)部分
//
//Shoe.m
//MemoryManage_1
//
//Createdbyjimmy.yangon11-2-19.
//Copyright2011__MyCompanyName__.Allrightsreserved.
//
#import"Shoe.h"
@implementationShoe
//構(gòu)造函數(shù)
-(id)init
{
if(self=[superinit]){
_shoeColor=@"black";
_shoeSize=35;
}
NSLog(@"一雙%@%d碼的鞋子造好了!",_shoeColor,_shoeSize);
return(self);
}
-(void)setColor:(NSString*)newColor
{
_shoeColor=newColor;
}
-(NSString*)Color
{
return_shoeColor;
}
-(void)setSize:(int)newSize
{
_shoeSize=newSize;
}
-(int)Size
{
return_shoeSize;
}
-(void)setColorAndSize:(NSString*)colorshoeSize:(int)size
{
[selfsetColor:color];
[selfsetSize:size];
}
//析構(gòu)函數(shù)
-(void)dealloc
{
NSLog(@"%@%d碼的鞋子!",_shoeColor,_shoeSize);
[superdealloc];
}
@end
Man.h定義部分
//
//Man.h
//MemoryManage_1
//
//Createdbyjimmy.yangon11-2-20.
//Copyright2011__MyCompanyName__.Allrightsreserved.
//
#import<Foundation/Foundation.h>
#import"Shoe.h"
@interfaceMan:NSObject{
NSString*_name;
Shoe*_shoe;
}
-(void)setName:(NSString*)name;
-(NSString*)Name;
-(void)wearShoe:(Shoe*)shoe;
@end
Man.m實(shí)現(xiàn)部分
//
//Man.m
//MemoryManage_1
//
//Createdbyjimmy.yangon11-2-20.
//Copyright2011__MyCompanyName__.Allrightsreserved.
//
#import"Man.h"
@implementationMan
//構(gòu)造函數(shù)
-(id)init
{
if(self=[superinit]){
_name=@"noname";
}
NSLog(@"新人\"%@\"出生了!",_name);
return(self);
}
-(void)setName:(NSString*)newName
{
_name=newName;
}
-(NSString*)Name
{
return_name;
}
-(void)wearShoe:(Shoe*)shoe
{
_shoe=shoe;
}
//析構(gòu)函數(shù)
-(void)dealloc
{
NSLog(@"\"%@\"信息!",_name);
[superdealloc];
}