歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

iOS基礎:retain,copy,assign及autorelease

一,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)。
Copyright © Linux教程網 All Rights Reserved