1. 程式人生 > >retain, copy, assign區別

retain, copy, assign區別

atomic 了解 bag enc 深入 oat In prop setname

一、retain, copy, assign區別

  • 假設你用malloc分配了一塊內存,並且把它的地址賦值給了指針a,後來你希望指針b也共享這塊內存,於是你又把a賦值給(assign)了b。此時a 和b指向同一塊內存,請問當a不再需要這塊內存,能否直接釋放它?答案是否定的,因為a並不知道b是否還在使用這塊內存,如果a釋放了,那麽b在使用這塊 內存的時候會引起程序crash掉。
  • 了解到1中assign的問題,那麽如何解決?最簡單的一個方法就是使用引用計數(reference counting),還是上面的那個例子,我們給那塊內存設一個引用計數,當內存被分配並且賦值給a時,引用計數是1。當把a賦值給b時引用計數增加到 2。這時如果a不再使用這塊內存,它只需要把引用計數減1,表明自己不再擁有這塊內存。b不再使用這塊內存時也把引用計數減1。當引用計數變為0的時候, 代表該內存不再被任何指針所引用,系統可以把它直接釋放掉。
  • 上面兩點其實就是assign和retain的區別,assign就是直接賦值,從而可能引起1中的問題,當數據為int, float等原生類型時,可以使用assign。retain就如2中所述,使用了引用計數,retain引起引用計數加1, release引起引用計數減1,當引用計數為0時,dealloc函數被調用,內存被回收。
  • copy是在你不希望a和b共享一塊內存時會使用到。a和b各自有自己的內存。
  • atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多線程環境下,原子操作是必要的,否則有可能引起錯 誤的結果。加了atomic,setter函數會變成下面這樣:
 if (property != newValue) {   
    [property release];   
    property = [newValue retain];   
}

二、深入理解一下(包括autorelease)

  • 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
    }

    調用時:
    OC ClassName *myName = [[ClassName alloc] init]; [classA setName:myName]; //retain count == 2 [myName release]; //retain count==1,在ClassA的dealloc中release name才能真正釋放內存。

    • 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,這個對象還是沒有被銷毀。
      上面這個例子應該這樣寫:
      OC 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)。

retain, copy, assign區別