內(nèi)存管理retain,assign,copy,strong,weak

IOS的對(duì)象都繼承于NSObject, 該對(duì)象有一個(gè)方法:retainCount ,內(nèi)存引用計(jì)數(shù)。 引用計(jì)數(shù)在很多技術(shù)都用到: window下的COM組件,多線程的信號(hào)量,讀寫(xiě)鎖,思想都一樣。

(一般情況下: 后面會(huì)討論例外情況)

alloc 對(duì)象分配后引用計(jì)數(shù)為1

retain 對(duì)象的引用計(jì)數(shù)+1

copy copy 一個(gè)對(duì)象變成新的對(duì)象(新內(nèi)存地址) 引用計(jì)數(shù)為1 原來(lái)對(duì)象計(jì)數(shù)不變

release 對(duì)象引用計(jì)數(shù)-1 如果為0釋放內(nèi)存

autorelease 對(duì)象引用計(jì)數(shù)-1 如果為0不馬上釋放,最近一個(gè)個(gè)pool時(shí)釋放

NSLog(@"sMessage retainCount:%u",[sMessage retainCount]);

內(nèi)存管理的原則就是最終的引用計(jì)數(shù)要平衡,

如果最后引用計(jì)數(shù)大于0 則會(huì)內(nèi)存泄露

如果引用 計(jì)數(shù)等于0還對(duì)該對(duì)象進(jìn)行操作,則會(huì)出現(xiàn)內(nèi)存訪問(wèn)失敗,crash 所以盡量設(shè)置為nil

這兩個(gè)問(wèn)題都很?chē)?yán)重,所以請(qǐng)一定注意內(nèi)存釋放和不用過(guò)后設(shè)置為nil

成員變量與屬性

實(shí)際情況并非上面那么簡(jiǎn)單,你可能需要在一個(gè)函數(shù)里調(diào)用另一個(gè)函數(shù)分配的變量這時(shí)候

有兩個(gè)選擇: 類成員變量和使用屬性

@interface TestMem: NSObject {

TestObject *m_testObject ; // 成員變量

TestObject *testObject; //成員變量

}

成員變量與上面的內(nèi)存管理是一致的,只是在不同的函數(shù)里要保持引用計(jì)數(shù)加減的平衡

所以要你要每次分配的時(shí)候檢查是否上次已經(jīng)分配了。是否還能調(diào)用

什么時(shí)候用屬性?

1. 把成員做為public.

2. outlet 一般聲明為屬性( 這個(gè)內(nèi)存于系統(tǒng)控制,但我們還是應(yīng)該做一樣操作,后面會(huì)講)

3. 如果很多函數(shù)都需要改變這個(gè)對(duì)象 ,或這個(gè)函數(shù)會(huì)觸發(fā)很多次,建議使用屬性。我們看看屬性函數(shù)展開(kāi)后是什么樣子:

// assign

-(void)setTestObject :(id)newValue{

testObject= newValue;

}

// retain

-(void)setTestObject :(id)newValue{

if (testObject!= newValue) {

[testObject release];

testObject= [newValue retain];

}

}

// copy

-(void)setTestObject :(id)newValue{

if (testObject != newValue) {

[testObject release];

testObject = [newValue copy];

}

}

asssign 相于于指針賦值,不對(duì)引用計(jì)數(shù)進(jìn)行操作,注意原對(duì)象不用了,一定要把這個(gè)設(shè)置為nil

retain 相當(dāng)于對(duì)原對(duì)象的引用計(jì)數(shù)加1

copy 不對(duì)原對(duì)象的引用計(jì)數(shù)改變,生成一個(gè)新對(duì)象引用計(jì)數(shù)為1

注意:

self.testObject 左值調(diào)用的是setTestObject 方法. 右值為get方法,get 方法比較簡(jiǎn)單不用說(shuō)了

而 真接testObject 使用的是成員變量

self.testObject = [[testObject alloc] init]; // 錯(cuò) reatin 兩次

testObject = [NSArray objectbyindex:0]; //錯(cuò) 不安全,沒(méi)有retain 后面release會(huì)出錯(cuò)

如果testObject已有值也會(huì)mem leak

自動(dòng)管理對(duì)象

IOS 提供了很多static(+) 創(chuàng)建對(duì)象的類方法,這些方面是靜態(tài)的,可以直接用類名

調(diào)用如:

NSString *testString = [NSString stringWithFormat:@"test" ];

testString 是自動(dòng)管理的對(duì)象,你不用relese 他,他有一個(gè)很大的retain count, release后數(shù)字不變。

5.?例外

有一些通過(guò)alloc 生成的對(duì)象相同是自動(dòng)管理的如:

NSString *testString = [[NSString alloc] initWithString:@"test1"];

retain count 同樣是很大的數(shù),沒(méi)辦法release

但為了代碼對(duì)應(yīng),還是應(yīng)該加上[ testString release];

不然xcode的Analyze 會(huì)認(rèn)識(shí)內(nèi)存leak, 但I(xiàn)nstruments leak 工具檢測(cè)是沒(méi)有的

自動(dòng)管理對(duì)象

IOS 提供了很多static(+) 創(chuàng)建對(duì)象的類方法,這些方面是靜態(tài)的,可以直接用類名

調(diào)用如:

NSString *testString = [NSString stringWithFormat:@"test" ];

testString 是自動(dòng)管理的對(duì)象,你不用relese 他,他有一個(gè)很大的retain count, release后數(shù)字不變。

5.?例外

有一些通過(guò)alloc 生成的對(duì)象相同是自動(dòng)管理的如:

NSString *testString = [[NSString alloc] initWithString:@"test1"];

retain count 同樣是很大的數(shù),沒(méi)辦法release

但為了代碼對(duì)應(yīng),還是應(yīng)該加上[ testString release];

不然xcode的Analyze 會(huì)認(rèn)識(shí)內(nèi)存leak, 但I(xiàn)nstruments leak 工具檢測(cè)是沒(méi)有的

IOS內(nèi)存管理詳解

copy?和 retain 的區(qū)別

copy: 建立一個(gè)索引計(jì)數(shù)為1的對(duì)象,然后釋放舊對(duì)象

retain:釋放舊的對(duì)象,將舊對(duì)象的值賦予輸入對(duì)象,再提高輸入對(duì)象的索引計(jì)數(shù)為1

那上面的是什么該死的意思呢?

Copy其實(shí)是建立了一個(gè)相同的對(duì)象,而retain不是:

比如一個(gè)NSString對(duì)象,地址為0×1111,內(nèi)容為@”STR”

Copy到另外一個(gè)NSString之后,地址為0×2222,內(nèi)容相同,新的對(duì)象retain為1,舊有對(duì)象沒(méi)有變化

retain到另外一個(gè)NSString之后,地址相同(建立一個(gè)指針,指針拷貝),內(nèi)容當(dāng)然相同,這個(gè)對(duì)象的retain值+1

也就是說(shuō),retain是指針拷貝,copy是內(nèi)容拷貝。哇,比想象的簡(jiǎn)單多了…

誤釋放對(duì)象

問(wèn)題一:

1.value = [array objectAtIndex:n]; //得到一個(gè)數(shù)組中的對(duì)象

2.[arry removeObjectAtIndex:n]; //卸載那個(gè)對(duì)象

?????value = [array objectAtIndex:n]; //得到一個(gè)數(shù)組中的對(duì)象

[arry removeObjectAtIndex:n]; //卸載那個(gè)對(duì)象

因?yàn)関alue得到了那個(gè)對(duì)象,但是由于另外一個(gè)擁有者release了該對(duì)象,所以其實(shí)value現(xiàn)在成了搖擺指針(無(wú)效數(shù)據(jù))

問(wèn)題二:

1.myArray = [NSArray array];

2....

3.[myArray release];

?????myArray = [NSArray array];

...

[myArray release];

NSArray返回的是一個(gè)自動(dòng)釋放對(duì)象,不僅myArray不應(yīng)該在一段時(shí)間后release,而應(yīng)該在適當(dāng)?shù)臅r(shí)候先retain,以防止該array被系統(tǒng)誤釋放。

問(wèn)題三:

1.rocket = [rocketLauncher aRocket];

2.[rocketLauncher release];

?????rocket = [rocketLauncher aRocket];

[rocketLauncher release];

和array這種數(shù)據(jù)收集類對(duì)象一樣,如果我們得到了一個(gè)類的子對(duì)象而不retain它,那么在原父類被釋放的時(shí)候,這個(gè)rocket其實(shí)也會(huì)失去其意義。

Cocoa不同內(nèi)存管理環(huán)境下的autorelease

H 混合內(nèi)存管理環(huán)境:垃圾收集法(Garbage Collection)+索引計(jì)數(shù)法(Reference Counting)

雖然大多數(shù)情況下混合環(huán)境是不被推薦的,但是如果在這個(gè)情況下,autorelease需要注意以下事項(xiàng):

垃圾收集混合環(huán)境下:應(yīng)該使用drain方法,因?yàn)閞elease在GC模式下沒(méi)有意義

索引計(jì)數(shù)環(huán)境下:drain和release對(duì)于autoreleasepool(自動(dòng)釋放池)的效果相同

對(duì)autorelease的誤解

A Cocoa的內(nèi)存管理分為 索引計(jì)數(shù)法(Reference Counting/ Retain Count)和 垃圾收集法(Garbage Collection)。而iPhone上目前只支持前者,所以autorelease就成為很多人的“捷徑”。

但是!autorelease其實(shí)并不是“自動(dòng)釋放”,不像垃圾收集法,對(duì)對(duì)象之間的關(guān)系偵測(cè)后發(fā)現(xiàn)垃圾-刪除。但是autorelease其實(shí)是“延后釋放”,在一個(gè)運(yùn)行周期后被標(biāo)記為autorelease會(huì)被釋放掉。

切記小心使用autorelease,理解autorelease,防止在你還需要該對(duì)象的時(shí)候已經(jīng)被系統(tǒng)釋放掉了。

Interface Builder參與的內(nèi)存管理問(wèn)題

要點(diǎn):

如果一個(gè)變量在類中被定義為了 IBOutlet 那么你無(wú)需對(duì)其進(jìn)行實(shí)例化,xib載入器會(huì)對(duì)其初始化。

如果一個(gè)變量在類中被定義為了 IBOutlet 那么你必須負(fù)責(zé)將其釋放。xib載入器不會(huì)幫忙的… …

*切不要初始化兩回,內(nèi)存會(huì)溢出,而且對(duì)象鎖定也會(huì)出錯(cuò)。

關(guān)于索引計(jì)數(shù)(Reference Counting)的問(wèn)題

1.*retain值 = 索引計(jì)數(shù)//(Reference Counting)

???*retain值 = 索引計(jì)數(shù)//(Reference Counting)

NSArray對(duì)象會(huì)retain(retain值加一)任何數(shù)組中的對(duì)象。當(dāng)NSArray被卸載(dealloc)的時(shí)候,所有數(shù)組中的對(duì)象會(huì)被執(zhí)行一次釋放(retain值減一)。不僅僅是NSArray,任何收集類(Collection Classes)都執(zhí)行類似操作。例如NSDictionary,甚至UINavigationController。

Alloc/init建立的對(duì)象,索引計(jì)數(shù)為1。無(wú)需將其再次retain。

[NSArray array]和[NSDate date]等“方法”建立一個(gè)索引計(jì)數(shù)為1的對(duì)象,但是也是一個(gè)自動(dòng)釋放對(duì)象。所以是本地臨時(shí)對(duì)象,那么無(wú)所謂了。如果是打算在全Class中使用的變量(iVar),則必須retain它。

缺省的類方法返回值都被執(zhí)行了“自動(dòng)釋放”方法。(*如上中的NSArray)

在類中的卸載方法“dealloc”中,release所有未被平衡的NS對(duì)象。(*所有未被autorelease,而retain值為1的)

NSString的內(nèi)存管理

如下實(shí)例:

1.aString = @"I am a string that 2 years old, man!";

aString = @"I am a string that 2 years old, man!";

這種情況下,字符串儲(chǔ)存和管理由系統(tǒng)做,我們不用操心。

1.aString = [NSString stringWithFormat:@"I am a string that %d years old, man!",2];

aString = [NSString stringWithFormat:@"I am a string that %d years old, man!",2];

第二種情況下,我們需要去retain和release這個(gè)字符串,系統(tǒng)不管。

Objective-C內(nèi)存管理

1,你初始化(alloc/init)的對(duì)象,你需要釋放(release)它。例如:

1.NSMutableArray aArray = [[NSArray alloc] init];

NSMutableArray aArray = [[NSArray alloc] init];

后,需要

1.[aArray release];

[aArray release];

2,你retain或copy的,你需要釋放它。例如:

1.[aArray retain]

[aArray retain]

后,需要

1.[aArray release];

[aArray release];

3,被傳遞(assign)的對(duì)象,你需要斟酌的retain和release。例如:

1.obj2 = [[obj1 someMethod] autorelease];

obj2 = [[obj1 someMethod] autorelease];

對(duì)象2接收對(duì)象1的一個(gè)自動(dòng)釋放的值,或傳遞一個(gè)基本數(shù)據(jù)類型(NSInteger,NSString)時(shí): 你或希望將對(duì)象2進(jìn)行retain,以防止它在被使用之前就被自動(dòng)釋放掉。但是在retain后,一定要在適當(dāng)?shù)臅r(shí)候進(jìn)行釋放。

為什么不能直接調(diào)用dealloc而是release

dealloc不等于C中的free,dealloc并不將內(nèi)存釋放,也不會(huì)將索引計(jì)數(shù)(Reference counting)降低。于是直接調(diào)用dealloc反而無(wú)法釋放內(nèi)存。

在Objective-C中,索引計(jì)數(shù)是起決定性作用的。

strong 和weak

iOS 5 中對(duì)屬性的設(shè)置新增了strong 和weak關(guān)鍵字來(lái)修飾屬性(iOS 5 之前不支持ARC)

strong 用來(lái)修飾強(qiáng)引用的屬性;

@property (strong) SomeClass * aObject;

對(duì)應(yīng)原來(lái)的

@property (retain) SomeClass * aObject; 和 @property (copy) SomeClass * aObject;

weak 用來(lái)修飾弱引用的屬性;

@property (weak) SomeClass * aObject;

對(duì)應(yīng)原來(lái)的

@property (assign) SomeClass * aObject;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • iOS目前已經(jīng)是ARC 時(shí)代。但對(duì)于要想了解ARC的內(nèi)存管理機(jī)制,還是依舊需要對(duì)MRC時(shí)代的內(nèi)存管理機(jī)制有深刻的理...
    ivylee_mr閱讀 1,791評(píng)論 0 2
  • 1. 內(nèi)總管理原則(引用計(jì)數(shù)) IOS的對(duì)象都繼承于NSObject, 該對(duì)象有一個(gè)方法:retainCount...
    lilinjianshu閱讀 2,244評(píng)論 0 2
  • 內(nèi)存管理 簡(jiǎn)述OC中內(nèi)存管理機(jī)制。與retain配對(duì)使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,081評(píng)論 1 16
  • iOS開(kāi)發(fā)中, 之前一直使用swift, 因此對(duì)于Objective-C的內(nèi)存管理機(jī)制長(zhǎng)期處于混亂的一知半解狀態(tài)....
    icetime17閱讀 944評(píng)論 1 8
  • 內(nèi)存管理是程序在運(yùn)行時(shí)分配內(nèi)存、使用內(nèi)存,并在程序完成時(shí)釋放內(nèi)存的過(guò)程。在Objective-C中,也被看作是在眾...
    蹲瓜閱讀 3,361評(píng)論 1 8

友情鏈接更多精彩內(nèi)容