IOS基礎:retain,copy,assign及autorelease

weixin_30639719發表於2020-04-05
一,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)。

轉載於:https://www.cnblogs.com/martin1009/archive/2012/06/18/2553184.html

相關文章