NSString 使用strong和copy的區(qū)別

Demo

@property(nonatomic, strong) NSString *strongStr;

@property(nonatomic, copy) NSString *copyyStr;
// 注:不能以alloc,new,copy,mutableCopy 作為開頭命名,比如:copyStr

聲明屬性"copyStr"報錯


圖片.png

第一種場景:用NSString直接賦值(錯誤案例)

// 第一種場景:用NSString直接賦值
NSString *originStr1 = [NSString stringWithFormat:@"hello,everyone"];

_strongStr = originStr1;
_copyyStr = originStr1;
    
NSLog(@"第一種場景:用NSString直接賦值");
NSLog(@"                          對象地址       對象指針地址      對象的值   ");
NSLog(@"originStr: %p , %p , %@", originStr1, &originStr1, originStr1);
NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr);
NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);

然后我們運行一下,打印結(jié)果如下圖:


圖片.png
結(jié)論:這種情況下,不管是用strong還是copy修飾的對象,其指向的地址都是originStr的地址。

第二種場景:用NSMutableString直接賦值(錯誤案例)

// 第二種場景:用NSMutableString直接賦值
NSMutableString *originStr2 = [NSMutableString stringWithFormat:@"hello,everyone"];

_strongStr = originStr2;
_copyyStr = originStr2;

[originStr2 setString:@"hello,QiShare"];
    
NSLog(@"第二種場景:用NSMutableString直接賦值");
NSLog(@"               對象地址         對象指針地址        對象的值   ");
NSLog(@"originStr: %p , %p , %@", originStr2, &originStr2, originStr2);
NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr);
NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);

然后我們運行一下,打印結(jié)果如下圖:


圖片.png

看到這里,同學(xué)們可能會有疑問,為什么不論是用strong還是copy修飾的對象,其指針指向的地址依然還是originStr的地址?為什么_copyyStr的值會變成“hello,QiShare”呢?不應(yīng)該是“hello,everyone”嗎?
咱們先不解釋,賣個關(guān)子,我們接著往下看。

第三種場景:用NSMutableString點語法賦值

// 第三種場景:用NSMutableString點語法賦值
NSMutableString *originStr3 = [NSMutableString stringWithFormat:@"hello,everyone"];
    
self.strongStr = originStr3;
self.copyyStr = originStr3;
    
[originStr3 setString:@"hello,QiShare"];
    
NSLog(@"第三種場景:用NSMutableString點語法賦值");
NSLog(@"               對象地址         對象指針地址        對象的值   ");
NSLog(@"originStr: %p , %p , %@", originStr3, &originStr3, originStr3);
NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr);
NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);

然后我們運行一下,打印結(jié)果如下圖:


圖片.png

OK,這回我們終于看到我們希望看到的結(jié)果了,
_copyyStr依然是“hello,everyone”,沒有變成“hello,QiShare”,
_copyyStr指針指向的地址不再是_originStr的地址。
細(xì)心的同學(xué)會發(fā)現(xiàn),第三種在賦值的時候用了點語法,而不是直接賦值。
除了將_strongStr = originStr2; 改為 self.strongStr = originStr3;
_copyyStr = originStr2;改為self.copyyStr = originStr3;
其余完全一樣。

也就是說,我們將_copyyStr = originStr2;改為 self.copyyStr = originStr3;才導(dǎo)致了_copyyStr的值在第三種情況下依然沒有改變,這是為什么呢?

當(dāng)我們用@property來聲明屬性變量時,編譯器會自動為我們生成一個以下劃線加屬性名命名的實例變量(@synthesize copyyStr = _copyyStr),并且生成其對應(yīng)的getter、setter方法。
當(dāng)我們用self.copyyStr = originStr賦值時,會調(diào)用coppyStr的setter方法,而_copyyStr = originStr 賦值時給_copyyStr實例變量直接賦值,并不會調(diào)用copyyStr的setter方法,而在setter方法中有一個非常關(guān)鍵的語句:
_copyyStr = [copyyStr copy];

結(jié)論:第三種場景中用self.copyyStr = originStr 賦值時,調(diào)用copyyStrsetter方法,setter方法對傳入的copyyStr做了次深拷貝生成了一個新的對象賦值給_copyyStr,所以_copyyStr指向的地址和對象值都不再和originStr相同。

第四種場景:用NSString點語法賦值

// 第四種場景:用NSString點語法賦值
NSString *originStr4 = [NSString stringWithFormat:@"hello,everyone"];

self.strongStr = originStr4;
self.copyyStr = originStr4;
    
NSLog(@"第三種場景:用NSMutableString點語法賦值");
NSLog(@"               對象地址         對象指針地址        對象的值   ");
NSLog(@"originStr: %p , %p , %@", originStr4, &originStr4, originStr4);
NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr);
NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);

這里我們將_copyyStr = originStr;改成了self.copyyStr = originStr;
這時候打印結(jié)果會是什么樣呢?


圖片.png

看了打印結(jié)果,可能有的同學(xué)會產(chǎn)生疑問,為什么用了self.copyyStr = originStr進(jìn)行賦值,調(diào)用了setter方法,調(diào)用了_copyyStr = [copyyStr copy]之后,_copyyName指向的地址和originStr指向的地址還是相同的呢?

原因:這里的copy是淺拷貝,并沒有生成新的對象

總結(jié):

  • 當(dāng)原字符串是NSString時,由于是不可變字符串,所以,不管使用strong還是copy修飾,都是指向原來的對象,copy操作只是做了一次淺拷貝。
  • 當(dāng)源字符串是NSMutableString時,strong只是將源字符串的引用計數(shù)加1,而copy則是對原字符串做了次深拷貝,從而生成了一個新的對象,并且copy的對象指向這個新對象。另外需要注意的是,這個copy屬性對象的類型始終是NSString,而不是NSMutableString,如果想讓拷貝過來的對象是可變的,就要使用mutableCopy。
所以,如果源字符串是NSMutableString的時候,使用strong只會增加引用計數(shù)。
但是copy會執(zhí)行一次深拷貝,會造成不必要的內(nèi)存浪費。而如果原字符串是NSString時,strong和copy效果一樣,就不會有這個問題。

但是,我們一般聲明NSString時,也不希望它改變,所以一般情況下,建議使用copy,這樣可以避免NSMutableString帶來的錯誤。

http://m.itdecent.cn/p/62913d6cbc40

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容