strong、copy,深拷貝、淺拷貝

文中所引用的對象如下解釋,顧名思義,簡單易懂

master.muStrStrong 指的用strong修飾的可變字符串
master.muStrCopy 指的用copy修飾的可變字符串
master.strStrong 指的是用strong修飾的不可變字符串
master.strCopy 指的是用copy修飾的不可變字符串

1.可變用strong的原因

NSMutableString應該使用strong類型,NSString使用copy類型,copy生成的是不可變對象,即用copy類型會強制將NSMutableString轉換爲NSString類型,所以無法使用NSMutableString的appendString等等方法,導致crash。


        master.muStrCopy = [NSMutableString stringWithString:@"123"];
        [master.muStrCopy appendString:@"33"];//執行到這句時 crash!!!!!!

2.不可變用copy的原因

假如有一個NSMutableString,現在用他給一個strong修飾 NSString賦值,那麼只是將NSString指向了NSMutableString所指向的位置,並對NSMUtbaleString計數器加一,此時,如果對NSMutableString進行修改,也會導致NSString的值修改,原則上這是不允許的.
例如

        master.muStrStrong = [NSMutableString stringWithString:@"123"];
        master.strStrong = master.muStr;
        [master.muStrStrong appendString:@"33"];
        NSLog(@"------%@,,,,%@",master.muStrStrong,master.strStrong);

打印結果:

——12333,,,,12333

改變了可變字符串的值後,不可變字符串也跟着改變,讓我們來看看它們的地址

打印地址後發現,他們指向了同一塊地址

—–0x10066c830,,,,0x10066c830

此時,不可變字符串在某種程度真的變成了可變字符串,所以這樣的結果是很荒謬的。

如果是copy修飾的NSString對象,在用NSMutableString給他賦值時,會進行深拷貝,及把內容也給拷貝了一份,兩者指向不同的位置,即使改變了NSMutableString的值,NSString的值也不會改變.
所以用copy是爲了安全,防止NSMutableString賦值給NSString時,前者修改引起後者值變化而用的.


3.深、淺拷貝

當使用NSString(A)給NSString(B)賦值,當B爲copy的時候也不會生成2個內存空間,而是指向同一個指針,即爲淺拷貝,當NSMutablestring(A)給NSString(B)賦值,當B爲copy的時候會生成2個內存空間,即爲深拷貝。

非集合類對象的copy與mutableCopy
系統非集合類對象指的是 NSString, NSNumber … 之類的對象。

下面先看個非集合類unmutable對象拷貝的例子

NSString *string =

@"origin";
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];

打印內存地址

string = 0x1000eda78
stringCopy = 0x1000eda78
stringMCopy = 0x17407e8c0

可以看到stringCopy和string的地址是一樣,說明進行了指針拷貝;而stringMCopy的地址和string不一樣,說明進行了內容拷貝;

再看mutable對象拷貝例子

NSMutableString *mString = [NSMutableString stringWithString:@"origin"];
NSString *stringCopy = [mString copy];
NSMutableString *mStringCopy = [mString copy];
NSMutableString *mStringMCopy = [mString mutableCopy];
[mStringCopy appendString:@"ww"];

運行上述代碼會在最後一行[mStringCopy appendString:@”mm”];處crash,原因是copy返回的對象是unmutable對象,刪掉該行,再次運行,打印內存地址

mString = 0x174266940
stringCopy = 0x1742294a0
mStringCopy = 0x1742294c0
mStringMCopy = 0x174266980

會發現四個對象的內存地址都不一樣,說明此時都是做內容拷貝。

綜上兩個例子,我們可以得出結論:

在非集合類對象中:


對unmutable對象進行copy操作是指針複製,mutableCopy操作是內容複製;
對mutable對象進行copy和mutableCopy都是內容複製。


用代碼簡單表示如下:

[unmutableObject copy] // 淺複製

[unmutableObject mutableCopy] //深複製

[mutableObject copy] //深複製

[mutableObject mutableCopy] //深複製

附:集合類對象的copy與mutableCopy的理論與其相同,不過此處的內容拷貝,僅僅是拷貝array這個對象,array集合內部的元素仍然是指針拷貝。

我們來看看一個例子

NSString *str0 = @"1";
        NSString *str1 = @"2";
        NSString *str2 = @"3";
        NSMutableArray *muArraySource = [[NSMutableArray alloc]initWithObjects:str0,str1,str2,nil];
        NSMutableArray *muArray = [[NSMutableArray alloc]init];
        muArray = [muArraySource copy];
        NSLog(@"%p,,,%p,,,%p",str0,str1,str2);
        NSLog(@"%p,,,%p",muArray,muArraySource);
        NSLog(@"%p,,,%p,,,%p",[muArraySource objectAtIndex:0],[muArraySource objectAtIndex:1],[muArraySource objectAtIndex:2]);

muArray = 0x100778c10
master.muArrayStrong = 0x1007787e0

正如我們所瞭解的,不可變集合執行copy進行了深拷貝

我們再來看看元素地址的變化

str0 = 0x100002068
[muArraySource objectAtIndex:0] = 0x100002068
str1 = 0x100002088
[muArraySource objectAtIndex:1] = 0x100002068
str2 = 0x1000020a8
引用塊內容

[muArraySource objectAtIndex:2] = 0x1000020a8

結果已經很明確了,可變數組進行了深拷貝,而其裏面的元素只進行了指針拷貝,即淺拷貝。



4.進一步的探索

1). 對於不可變對象的copy,屬於淺拷貝,無論被賦值對象是copy還是strong,都指向了這塊地址。

Master *master = [[Master alloc]init];
        NSString *temp = [[NSString alloc]init];
        temp = @"123";
        master.strCopy = [temp copy];
        master.strStrong = [temp copy];
        NSLog(@"%p,,,,%p,,,,%p",temp,master.strCopy,master.strStrong);
        temp = @"222";
        NSLog(@"%p,,,,%p,,,,%p",temp,master.strCopy,master.strStrong);
        NSLog(@"%@,,,,%@,,,,%@",temp,master.strCopy,master.strStrong);

0x100002068,,,,0x100002068,,,,0x100002068

當不可變字符串改變後,其內存會發生變化,可它們原來的指針仍指向這塊內存

0x100002088,,,,0x100002068,,,,0x100002068

222,,,,123,,,,123


2). [master.muStrStrong copy]; 不等於 master.muStrStrong

先看 [master.muStrStrong copy]; 的實例

Master *master = [[Master alloc]init];
        master.muStrStrong = [NSMutableString stringWithString:@“123”];
        master.strCopy = [master.muStr copy];
        master.strStrong = [master.muStr copy];
        NSLog(@"%p,,,,%p,,,,%p",master.muStrStrong,master.strCopy,master.strStrong);
        [master.muStrStrong appendString:@"33"];
        NSLog(@"------%p,,,,%p,,,,%p",master.muStrStrong,master.strCopy,master.strStrong);

master.muStrStrong = 0x10063c800
master.strCopy = 0x33323135
master.strStrong = 0x33323135

可變字符串改變後

master.muStrStrong = 0x10063c800
master.strCopy = 0x33323135
master.strStrong = 0x33323135

於是,muStrStrong執行copy進行了深拷貝,生成了新的對象,無論是copy還是strong修飾的字符串都指向了新生成對象的內存。我們也知道了,可變字符發生改變時所在地址不會發生變化。

再看 master.muStrStrong 的實例

        master.muStrStrong = [NSMutableString stringWithString:@"123"];
        master.strCopy = master.muStrStrong;
        master.strStrong = master.muStrStrong;
        [master.muStrStrong appendString:@"33"];
        NSLog(@"%p,,,,%p,,,,%p",master.muStrStrong,master.strCopy,master.strStrong);

master.muStrStrong = 0x10050a800
master.strCopy = 0x3332313
master.strStrong = 0x10050a800

此時strCopy進行了深拷貝,就如同賦值的muStrStrong執行copy一樣。
但是這兩種情況無論如何用copy修飾的NSString都進行了深拷貝,沒有違揹我們的意願


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