assign、retain和copy的區別

一、assign屬性

  當數據類型爲int、float等原生類型時,可以使用assign,否則可能導致內存泄露。例如當使用malloc分配了一塊內存,並把它的地址賦值給了指針a,後來如果希望指針b也共享這塊內存,於是講a賦值給(assgin)b。這時就用到了assgin,此時a和b指向同一塊內存。但是現在問題出現了,當a不再需要這塊內存時,能都直接釋放呢?肯定是不能的,因爲a並不知道b是否還在使用這塊內存,如果a釋放了,那麼b在使用這塊內存的時候引起程序crash掉。

二、retain屬性

  retain屬性就是爲了解決上述問題而提出的,使用了引用計數(reference counting),還是上面那個例子,我們給那塊內存設一個引用計數,當內存唄分配並且賦值給a時,引用計數是1.當把a賦值給b時引用計數增加到2.這時如果a不再使用這塊內存,它只需要把引用計數減1,表明自己不再擁有這塊內存。b不再使用這塊內存時也把引用計數減1.當引用計數變爲0的時候,代表該內存不再被任何指針所引用,系統可以直接釋放掉。此時系統自動調用dealloc函數,內存被回收。

三、copy屬性

copy是創建一個新對象,兩個對象內容相同,舊對象沒有變化。新的對象retain爲1,與舊有對象的引用計數不變。舊對象發生改變不影響新對象,copy減少對象對上下文的依賴。 

在iOS開發中我們一般都這麼定義:@property (nonatomic,copy) NSString *name,而不這麼定義:@property (nonatomic,retain) NSString *name,兩者的差別就在一個使用copy,一個使用retain。 這是爲什麼呢? 在說明白retain和copy的區別,首先需要明白深複製和淺複製的概念。 

1 深複製:內容拷貝,源對象和副本對象指的是兩個不同的對象,源對象引用計數器不變,副本對象引用計數器爲1 

2 淺複製:指針拷貝,源對象和副本對象指的都是同一個對象,對象引用計數器+1,相當於retain

只有不可變對象創建不可變副本(copy)纔是淺複製,其它的都是深複製 

下面通過實驗來說明copy和retain的區別。

@interface ViewController ()
@property (nonatomic,copy) NSString *name;
@property (nonatomic,retain) NSString *name2;
@end

-(void)test{
    NSString *str = @"我是不可變的";
    self.name = str;
    self.name2 = str;
    NSLog(@"   str:  %p",str);
    NSLog(@"  copy:  %p",self.name);
    NSLog(@"retain:  %p",self.name2);

}
-(void)test2{
    NSMutableString *str = [NSMutableString stringWithString:@"我是可變的"];
    self.name = str;
    self.name2 = str;
    NSLog(@"   strM:  %p",str);
    NSLog(@"   copy:  %p",self.name);
    NSLog(@"retain:  %p",self.name2);
}

兩次執行的結果如下:

   str:  0x7b140
  copy:  0x7b140
retain:  0x7b140

   str:  0x9c142b80
  copy:  0x9c140e60
retain:  0x9c142b80

首先,在test中,str指向一個不可變的NSString對象,地址爲0x7b140,然後str分別給name和name2賦值,由於name和name2都是NSString對象,所有都屬於淺複製,賦值後都是指向str對象地址0x7b140,所有打印結果三者指向同一個對象。 其次,在test2中,str指向一個可變的NSMutableString對象,地址爲0x9c140e60,然後分別給name和name2賦值,此時copy對應的name是深複製,所以會複製出另一個對象,地址爲0x7c148b80。而retain對應的name2依然指向str對象地址0x9c142b80,所以打印結果是str和name2對應同一地址,name對應另一個地址。 
所以得出結論: 
(1)copy是創建一個新對象,兩個對象內容相同,舊對象沒有變化。新的對象retain爲1,與舊有對象的引用計數不變。舊對象發生改變不影響新對象,copy減少對象對上下文的依賴。 
(2)retain屬性表示兩個對象地址相同(建立一個指針,指針拷貝),內容相同,這個對象的retain值+1。兩個對象要改變就一起改變。 
(3)如果把一個對象賦值給另一個對象(如上面把str賦值給name或name2),如果該對象是不可變的,那麼另一個對象是copy或者retain都可以,
沒區別;把一個對象賦值給另一個對象,如果該對象是可變的,並且希望另一個對象隨着該對象變化而變化,則可以把另一個對象設置爲retain(如上面把str賦值給name2);如果希望另一個對象不隨着該對象變化而變化,則可以把另一個對象設置爲copy(如上面把str賦值給name)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章