retain和strong、assign和weak的區別

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]);html

內存管理的原則就是最終的引用計數要平衡,
若是最後引用計數大於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 leakxcode

 

自動管理對象
IOS 提供了不少static(+) 建立對象的類方法,這些方面是靜態的,能夠直接用類名
調用如:
NSString *testString = [NSString stringWithFormat:@"test" ];
testString 是自動管理的對象,你不用relese 他,他有一個很大的retain count, release後數字不變。

5. 例外
有一些經過alloc 生成的對象相同是自動管理的如:
NSString *testString = [[NSString alloc] initWithString:@"test1"];
retain count 一樣是很大的數,沒辦法release
但爲了代碼對應,仍是應該加上[ testString release];
否則xcode的Analyze 會認識內存leak, 但Instruments leak 工具檢測是沒有的安全

 

 

自動管理對象
IOS 提供了不少static(+) 建立對象的類方法,這些方面是靜態的,能夠直接用類名
調用如:
NSString *testString = [NSString stringWithFormat:@"test" ];
testString 是自動管理的對象,你不用relese 他,他有一個很大的retain count, release後數字不變。

5. 例外
有一些經過alloc 生成的對象相同是自動管理的如:
NSString *testString = [[NSString alloc] initWithString:@"test1"];
retain count 一樣是很大的數,沒辦法release
但爲了代碼對應,仍是應該加上[ testString release];
否則xcode的Analyze 會認識內存leak, 但Instruments leak 工具檢測是沒有的多線程

 

 

 

IOS內存管理詳解

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

誤釋放對象
問題一:工具

view plaincopy to clipboardprint?ui

1.  value = [array objectAtIndex:n]; //獲得一個數組中的對象spa

2.  [arry removeObjectAtIndex:n]; //卸載那個對象線程

      value = [array objectAtIndex:n]; //獲得一個數組中的對象
      [arry removeObjectAtIndex:n]; //卸載那個對象

由於value獲得了那個對象,可是因爲另一個擁有者release了該對象,因此其實value如今成了搖擺指針(無效數據)

問題二:

1.  myArray = [NSArray array];

2.  ...

3.  [myArray release];

      myArray = [NSArray array];
       ...
      [myArray release];

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

問題三:

1.  rocket = [rocketLauncher aRocket];

2.  [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)的問題

view plaincopy to clipboardprint?

1.  *retain值 = 索引計數//(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的內存管理
以下實例:

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

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

這種狀況下,字符串儲存和管理由系統作,咱們不用操心。

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這個字符串,系統無論。

Objective-C內存管理
1,你初始化(alloc/init)的對象,你須要釋放(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)的對象,你須要斟酌的retain和release。例如:

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

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;

 

轉自:http://blog.sina.com.cn/s/blog_5fb39f910101ak04.html

相關文章
相關標籤/搜索