深拷貝和淺拷貝 copy與strong修飾變數的區別

佐籩發表於2018-10-31

深拷貝就是把內容拷貝一份,生成一個新的物件,新物件計數器為1, 源物件計數器不變。

淺拷貝就是指標拷貝,把地址拷貝出來一份(副本),副本和源地址指向同一個物件,源物件計數器加1,源物件和副本的計數器相同。


OC中存在copy和mutablecopy兩種拷貝函式,只要呼叫了copy不管是NSString,NSDictionary、NSArray還是NSMutableString、NSMutableDictionary、NSMutableArray拷貝出來的都是不可變的副本。

當呼叫mutablecopy時,拷貝出來的都是可變的副本。可變物件或者不可變物件mutablecopy都產生一個新的物件,引用計數為1,源物件的計數不變。

OC設定copy語法本事就是為了改變副本而不去影響源物件,所以既然copy出來的都不可變,自然也不會產生一個新的物件,相當於對源物件進行了retain操作。可變物件進行copy操作,可變物件變成了不可變物件,結構上發生了改變,所以說就是深拷貝。

總的來說就是:不可變物件的copy操作是淺拷貝,其他操作都是深拷貝。

可變物件的copy和mutalbecopy方法都是深拷貝,而且都是單層拷貝。舉例說明一下,陣列a和陣列b,讓陣列b = [a copy] 或者 b = [a mutableCopy],雖然b的地址和a的地址不同,但是裡面的陣列元素的地址和源陣列裡面的物件的地址還是相同的,也就是說陣列內容還是指向原陣列裡面的元素的。


copy和strong修飾變數的區別

先看一段程式碼執行的結果,宣告兩個屬性:

@property (nonatomic, strong) NSString *rStr;
@property (nonatomic, copy) NSString *cStr;複製程式碼

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];
    self.rStr = mStr;
    self.cStr = mStr;
    NSLog(@"mStr:%@, =%p, =%p",mStr, mStr, &mStr);
    NSLog(@"rStr:%@, =%p, =%p",_rStr, _rStr, &_rStr);
    NSLog(@"cStr:%@, =%p, =%p",_cStr, _cStr, &_cStr);
}複製程式碼

假設,mStr物件的地址是0x123,也就是說字串abc的首地址是0x123,mStr變數自身在記憶體中的地址為0x789;

當執行完mStr賦值給strong(retain)的rStr時,rStr物件的地址是0x123,rStr變數自身在記憶體中的地址是0x345,rStr和mStr指向同樣的地址,他們指向的是同一個物件abc;

當執行完mStr賦值給copy的cStr時,cStr物件的地址是0x258,cStr變數自身在記憶體中的地址是0x434,cStr和mStr指向的地址是不一樣的,他們指向的是不同的物件。

在執行下面一句程式碼:

[mStr appendString:@"de"];
複製程式碼

結果,

使用strong的字串rStr的值:@"abcde",

使用copy的字串cStr的值:@"abc"

所以,當把NSMutableString賦值給NSString的時候,如果希望字串的值跟著賦值的字串值變化,可以使用strong、retain。strong或retain僅僅是指標引用,增加了引用計數,所以當源字串改變的時候,它也會跟著改變(淺拷貝)。而copy宣告的變數,不會跟著改變,是深拷貝。

如果賦值是NSString物件,那麼使用copy還是strong或者retain,結果是一樣的。


簡單描述一下用strong和weak來修飾成員變數的對比:

用weak修飾,初始化之後就會被釋放掉,具體可參考下面連結blog.csdn.net/aaaaazq/art…


相關文章