retain 和copy的區別

weixin_34075551發表於2018-02-24

在ios開發中我們一般都這麼定義:@property (nonatomic,copy) NSString *name,而不這麼定義:@property (nonatomic,retain) NSString *name,兩者的差別就在一個使用copy,一個使用retain。
一直以來都不明白為什麼,今天通過查閱資料總算弄明白了,所以記錄一下。
在說明白retain和copy的區別,首先需要明白深複製和淺複製的概念。
1 深複製:內容拷貝,源物件和副本物件指的是兩個不同的物件,源物件引用計數器不變,副本物件引用計數器為1
2 淺複製:指標拷貝,源物件和副本物件指的都是同一個物件,物件引用計數器+1,相當於retain

只有不可變物件建立不可變副本(copy)才是淺複製,其它的都是深複製
上面的結論至關重要,大家可以對NSString和NSMutableString分別測試,在此不再贅述。
下面通過實驗來說明copy和retain的區別。

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


-(void)test{
    NSString *str = @"fffff";
    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:@"ffffff"];
    self.name = str;
    self.name2 = str;
    NSLog(@"   strM:  %p",str);
    NSLog(@"   copy:  %p",self.name);
    NSLog(@"retaini:  %p",self.name2);
}

先執行test,再執行test2,兩次執行的結果如下:

1716313-8e61e0fab2005147.png
20151209193606057.png
1716313-c14c024400679086.png
20151209193635805.png

所以得出結論:
(1)copy是建立一個新物件,兩個物件內容相同,舊物件沒有變化。新的物件retain為1,與舊有物件的引用計數不變。舊物件發生改變不影響新物件,copy減少物件對上下文的依賴。
(2)retain屬性表示兩個物件地址相同(建立一個指標,指標拷貝),內容相同,這個物件的retain值+1。兩個物件要改變就一起改變。
(3)如果把一個物件賦值給另一個物件(如上面把str賦值給name或name2),如果該物件是不可變的,那麼另一個物件是copy或者retain都可以,沒區別;把一個物件賦值給另一個物件,如果該物件是可變的,並且希望另一個物件隨著該物件變化而變化,則可以把另一個物件設定為retain(如上面把str賦值給name2);如果希望另一個物件不隨著該物件變化而變化,則可以把另一個物件設定為copy(如上面把str賦值給name)

相關文章