你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> IOS內存管理retain,assign,copy,strong,weak

IOS內存管理retain,assign,copy,strong,weak

編輯:IOS開發綜合

IOS的對象都繼承於NSObject, 該對象有一個方法:retainCount ,內存引用計數。 引用計數在很多技術都用到: Window下的COM組件,多線程的信號量,讀寫鎖,思想都一樣。

(一般情況下: 後面會討論例外情況)
alloc 對象分配後引用計數為1
retain 對象的引用計數+1
copy copy 一個對象變成新的對象(新內存地址) 引用計數為1 原來對象計數不變

release 對象引用計數-1 如果為0釋放內存
autorelease 對象引用計數-1 如果為0不馬上釋放,最近一個個pool時釋放

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

內存管理的原則就是最終的引用計數要平衡,
如果最後引用計數大於0 則會內存洩露
如果引用 計數等於0還對該對象進行操作,則會出現內存訪問失敗,crash 所以盡量設置為nil
這兩個問題都很嚴重,所以請一定注意內存釋放和不用過後設置為nil

成員變量與屬性
實際情況並非上面那麼簡單,你可能需要在一個函數裡調用另一個函數分配的變量這時候
有兩個選擇: 類成員變量和使用屬性

@interface TestMem: NSObject {
    TestObject *m_testObject ; // 成員變量
    TestObject *testObject; //成員變量
}

成員變量與上面的內存管理是一致的,只是在不同的函數裡要保持引用計數加減的平衡
所以要你要每次分配的時候檢查是否上次已經分配了。是否還能調用
什麼時候用屬性?
1. 把成員做為public.
2. outlet 一般聲明為屬性( 這個內存於系統控制,但我們還是應該做一樣操作,後面會講)
3. 如果很多函數都需要改變這個對象 ,或這個函數會觸發很多次,建議使用屬性。我們看看屬性函數展開後是什麼樣子:

// 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 相於於指針賦值,不對引用計數進行操作,注意原對象不用了,一定要把這個設置為nil
retain 相當於對原對象的引用計數加1
copy 不對原對象的引用計數改變,生成一個新對象引用計數為1
注意:
self.testObject 左值調用的是setTestObject 方法. 右值為get方法,get 方法比較簡單不用說了
而 真接testObject 使用的是成員變量

self.testObject = [[testObject alloc] init]; // 錯 reatin 兩次
testObject = [NSArray objectbyindex:0]; //錯 不安全,沒有retain 後面release會出錯

如果testObject已有值也會mem leak

自動管理對象
IOS 提供了很多static(+) 創建對象的類方法,這些方面是靜態的,可以直接用類名
調用如:

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

testString 是自動管理的對象,你不用relese 他,他有一個很大的retain count, release後數字不變。

例外
有一些通過alloc 生成的對象相同是自動管理的如:

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

retain count 同樣是很大的數,沒辦法release
但為了代碼對應,還是應該加上[ testString release];
不然xcode的Analyze 會認識內存leak, 但Instruments leak 工具檢測是沒有的

copy 和 retain 的區別
copy: 建立一個索引計數為1的對象,然後釋放舊對象
retain:釋放舊的對象,將舊對象的值賦予輸入對象,再提高輸入對象的索引計數為1
那上面的是什麼該死的意思呢?
Copy其實是建立了一個相同的對象,而retain不是:
比如一個NSString對象,地址為0×1111,內容為@”STR”
Copy到另外一個NSString之後,地址為0×2222,內容相同,新的對象retain為1,舊有對象沒有變化
retain到另外一個NSString之後,地址相同(建立一個指針,指針拷貝),內容當然相同,這個對象的retain值+1
也就是說,retain是指針拷貝,copy是內容拷貝。哇,比想象的簡單多了…

誤釋放對象
問題一:

value = [array objectAtIndex:n]; //得到一個數組中的對象

[arry removeObjectAtIndex:n]; //卸載那個對象

value = [array objectAtIndex:n]; //得到一個數組中的對象

[arry removeObjectAtIndex:n]; //卸載那個對象

因為value得到了那個對象,但是由於另外一個擁有者release了該對象,所以其實value現在成了搖擺指針(無效數據)

問題二:

myArray = [NSArray array];

[myArray release];

myArray = [NSArray array]; …

[myArray release];

NSArray返回的是一個自動釋放對象,不僅myArray不應該在一段時間後release,而應該在適當的時候先retain,以防止該array被系統誤釋放。

問題三:

rocket = [rocketLauncher aRocket];

[rocketLauncher release];

rocket = [rocketLauncher aRocket];

[rocketLauncher release];

和array這種數據收集類對象一樣,如果我們得到了一個類的子對象而不retain它,那麼在原父類被釋放的時候,這個rocket其實也會失去其意義。

Cocoa不同內存管理環境下的autorelease
H 混合內存管理環境:垃圾收集法(Garbage Collection)+索引計數法(Reference Counting)
雖然大多數情況下混合環境是不被推薦的,但是如果在這個情況下,autorelease需要注意以下事項:
垃圾收集混合環境下:應該使用drain方法,因為release在GC模式下沒有意義
索引計數環境下:drain和release對於autoreleasepool(自動釋放池)的效果相同

對autorelease的誤解
A Cocoa的內存管理分為 索引計數法(Reference Counting/ Retain Count)和 垃圾收集法(Garbage Collection)。而iPhone上目前只支持前者,所以autorelease就成為很多人的“捷徑”。
但是!autorelease其實並不是“自動釋放”,不像垃圾收集法,對對象之間的關系偵測後發現垃圾-刪除。但是autorelease其實是“延後釋放”,在一個運行周期後被標記為autorelease會被釋放掉。
切記小心使用autorelease,理解autorelease,防止在你還需要該對象的時候已經被系統釋放掉了。

Interface Builder參與的內存管理問題
要點:
如果一個變量在類中被定義為了 IBOutlet 那麼你無需對其進行實例化,xib載入器會對其初始化。
如果一個變量在類中被定義為了 IBOutlet 那麼你必須負責將其釋放。xib載入器不會幫忙的… …
*切不要初始化兩回,內存會溢出,而且對象鎖定也會出錯。

關於索引計數(Reference Counting)的問題

*retain值 = 索引計數//(Reference Counting)

NSArray對象會retain(retain值加一)任何數組中的對象。當NSArray被卸載(dealloc)的時候,所有數組中的對象會被執行一次釋放(retain值減一)。不僅僅是NSArray,任何收集類(Collection Classes)都執行類似操作。例如NSDictionary,甚至UINavigationController。
Alloc/init建立的對象,索引計數為1。無需將其再次retain。
[NSArray array]和[NSDate date]等“方法”建立一個索引計數為1的對象,但是也是一個自動釋放對象。所以是本地臨時對象,那麼無所謂了。如果是打算在全Class中使用的變量(iVar),則必須retain它。
缺省的類方法返回值都被執行了“自動釋放”方法。(*如上中的NSArray)
在類中的卸載方法“dealloc”中,release所有未被平衡的NS對象。(*所有未被autorelease,而retain值為1的)

NSString的內存管理
如下實例:

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

這種情況下,字符串儲存和管理由系統做,我們不用操心。

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

第二種情況下,我們需要去retain和release這個字符串,系統不管。

Objective-C內存管理
你初始化(alloc/init)的對象,你需要釋放(release)它。例如:

NSMutableArray aArray = [[NSArray alloc] init];後,需要

[aArray release];

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

[aArray retain]

後,需要

[aArray release];

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

obj2 = [[obj1 someMethod] autorelease];

對象2接收對象1的一個自動釋放的值,或傳遞一個基本數據類型(NSInteger,NSString)時: 你或希望將對象2進行retain,以防止它在被使用之前就被自動釋放掉。但是在retain後,一定要在適當的時候進行釋放。

為什麼不能直接調用dealloc而是release
dealloc不等於C中的free,dealloc並不將內存釋放,也不會將索引計數(Reference counting)降低。於是直接調用dealloc反而無法釋放內存。
在Objective-C中,索引計數是起決定性作用的。

strong 和weak

IOS 5 中對屬性的設置新增了strong 和weak關鍵字來修飾屬性(iOS 5 之前不支持ARC)

strong 用來修飾強引用的屬性;

@property (strong) SomeClass * aObject;

對應原來的
@property (retain) SomeClass * aObject; 和 @property (copy) SomeClass * aObject;

weak 用來修飾弱引用的屬性;
@property (weak) SomeClass * aObject;
對應原來的

@property (assign) SomeClass * aObject;

以上就是IOS內存管理retain,assign,copy,strong,weak的全文介紹,希望對您學習和使用ios應用開發有所幫助.

【IOS內存管理retain,assign,copy,strong,weak】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved