http://www.cnblogs.com/martin1009/archive/2012/06/18/2553184.html
一,retain, copy, assign區別
1. 假設你用malloc分配了一塊記憶體,並且把它的地址賦值給了指標a,後來你希望指標b也共用這塊記憶體,於是你又把a賦值給(assign)了b。此時a 和b指向同一塊記憶體,請問當a不再需要這塊記憶體,能否直接釋放它。答案是否定的,因為a並不知道b是否還在使用這塊記憶體,如果a釋放了,那麼b在使用這塊記憶體的時候會引起程式crash掉。
2. 瞭解到1中assign的問題,那麼如何解決。最簡單的一個方法就是使用引用計數(reference counting),還是上面的那個例子,我們給那塊記憶體設一個引用計數,當記憶體被分配並且賦值給a時,引用計數是1。當把a賦值給b時引用計數增加到 2。這時如果a不再使用這塊記憶體,它只需要把引用計數減1,表明自己不再擁有這塊記憶體。b不再使用這塊記憶體時也把引用計數減1。當引用計數變為0的時候,代表該記憶體不再被任何指標所引用,系統可以把它直接釋放掉。
3. 上面兩點其實就是assign和retain的區別,assign就是直接賦值,從而可能引起1中的問題,當資料為int, float等原生類型時,可以使用assign。retain就如2中所述,使用了引用計數,retain引起引用計數加1, release引起引用計數減1,當引用計數為0時,dealloc函數被調用,記憶體被回收。
4. copy是在你不希望a和b共用一塊記憶體時會使用到。a和b各自有自己的記憶體。
5. atomic和nonatomic用來決定編譯器產生的getter和setter是否為原子操作。在多線程環境下,原子操作是必要的,否則有可能引起錯誤的結果。加了atomic,setter函數會變成下面這樣:
if (property != newValue) {
[property release];
property = [newValue retain];
}
二,深入理解一下(包括autorelease)
1. retain之後count加一。alloc之後count就是1,release就會調用dealloc銷毀這個對象。
如果 retain,需要release兩次。通常在method中把參數賦給成員變數時需要retain。
例如:
ClassA有 setName這個方法:
-(void)setName:(ClassName *) inputName
{
name = inputName;
[name retain]; //此處retian,等同於[inputName retain],count等於2
}
調用時:
ClassName *myName = [[ClassName alloc] init];
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,在ClassA的dealloc中release name才能真正釋放記憶體。
2. autorelease 更加tricky,而且很容易被它的名字迷惑。我在這裡要強調一下:autorelease不是garbage collection,完全不同於Java或者.Net中的GC。
autorelease和 範圍沒有任何關係。
autorelease 原理:
a.先建立一個autorelease pool
b.對象從這個autorelease pool裡面產生。
c.對象產生 之後調用autorelease函數,這個函數的作用僅僅是在autorelease pool中做個標記,讓pool記得將來release一下這個對象。
d.程式結束時,pool本身也需要rerlease, 此時pool會把每一個標記為autorelease的對象release一次。如果某個對象此時retain count大於1,這個對象還是沒有被銷毀。
上面這個例子應該這樣寫:
ClassName *myName = [[[ClassName alloc] init] autorelease];//標記為autorelease
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,注意,在ClassA的dealloc中不能release name,否則release pool時會release這個retain count為0的對象,這是不對的。
記住一點:如果這個對象是你alloc或者new出來的,你就需要調用release。如果使用autorelease,那麼僅在發生過retain的時候release一次(讓retain count始終為1)。