iOS Strong和Copy的區(qū)別

首先聲明了兩個(gè)NSString屬性篷店,如下:
@property(nonatomic, strong) NSString *strongStr;
@property(nonatomic, copy) NSString *copyyStr;

下面我們分別以NSString和NSMutableString舉例
NSString場(chǎng)景一
// 使用NSString直接賦值
NSString *originStr = [NSString stringWithFormat:@"hello,originStr"];

_strongStr = originStr;
_copyyStr = originStr;

NSLog(@"originStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", originStr, &originStr, originStr);
NSLog(@"strongStr 對(duì)象地址: %p ,對(duì)象指針地址: %p ,對(duì)象的值:%@", _strongStr, &_strongStr, _strongStr);
NSLog(@"copyyStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", _copyyStr, &_copyyStr, _copyyStr);

控制臺(tái)輸出
2018-09-06 09:06:31.741210+0800 PropertyDemo[2451:226039] originStr 對(duì)象地址: 0x60400025ff20 ,對(duì)象指針地址:0x7ffee80f9a48 ,對(duì)象的值:hello,originStr
2018-09-06 09:06:31.741346+0800 PropertyDemo[2451:226039] strongStr 對(duì)象地址: 0x60400025ff20 ,對(duì)象指針地址: 0x7f9561c12cc0 ,對(duì)象的值:hello,originStr
2018-09-06 09:06:31.741466+0800 PropertyDemo[2451:226039] copyyStr 對(duì)象地址: 0x60400025ff20 ,對(duì)象指針地址:0x7f9561c12cc8 ,對(duì)象的值:hello,originStr

結(jié)論:這種情況下矾屯,不管是用strong還是copy修飾的對(duì)象,其指向的地址都是originStr的地址枝誊。
NSString場(chǎng)景二
// 第二種場(chǎng)景:用NSString直接賦值
NSString *originStr = [NSString stringWithFormat:@"hello,originStr"];

self.strongStr = originStr;
self.copyyStr = originStr;

NSLog(@"originStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", originStr, &originStr, originStr);
NSLog(@"strongStr 對(duì)象地址: %p ,對(duì)象指針地址: %p ,對(duì)象的值:%@", _strongStr, &_strongStr, _strongStr);
NSLog(@"copyyStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", _copyyStr, &_copyyStr, _copyyStr);

控制臺(tái)輸出
2018-09-06 09:33:35.203366+0800 PropertyDemo[2804:257010] originStr 對(duì)象地址: 0x604000443f00 ,對(duì)象指針地址:0x7ffee73bba28 ,對(duì)象的值:hello,originStr
2018-09-06 09:33:35.203533+0800 PropertyDemo[2804:257010] strongStr 對(duì)象地址: 0x604000443f00 ,對(duì)象指針地址: 0x7f8c40e09240 ,對(duì)象的值:hello,originStr
2018-09-06 09:33:35.203645+0800 PropertyDemo[2804:257010] copyyStr 對(duì)象地址: 0x604000443f00 ,對(duì)象指針地址:0x7f8c40e09248 ,對(duì)象的值:hello,originStr

為什么用了self.copyyStr = originStr進(jìn)行賦值宝恶,調(diào)用了setter方法之后烙丛,copyyStr指向的地址和originStr指向的地址還是相同的呢祭埂?
原因:這里的copy是淺拷貝面氓,并沒(méi)有生成新的對(duì)象
NSMutableString場(chǎng)景一
// 使用NSMutableString直接賦值
NSMutableString *originStr = [NSMutableString stringWithFormat:@"hello,originStr"];

_strongStr = originStr;
_copyyStr = originStr;

[originStr setString:@"hello,I changed"];

NSLog(@"originStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", originStr, &originStr, originStr);
NSLog(@"strongStr 對(duì)象地址: %p ,對(duì)象指針地址: %p ,對(duì)象的值:%@", _strongStr, &_strongStr, _strongStr);
NSLog(@"copyyStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", _copyyStr, &_copyyStr, _copyyStr);

控制臺(tái)輸出
2018-09-06 09:17:25.259841+0800 PropertyDemo[2652:239951] originStr 對(duì)象地址: 0x600000259290 ,對(duì)象指針地址:0x7ffeeeb8aa28 ,對(duì)象的值:hello,I changed
2018-09-06 09:17:25.259991+0800 PropertyDemo[2652:239951] strongStr 對(duì)象地址: 0x600000259290 ,對(duì)象指針地址: 0x7f86bae0d3d0 ,對(duì)象的值:hello,I changed
2018-09-06 09:17:25.260125+0800 PropertyDemo[2652:239951] copyyStr 對(duì)象地址: 0x600000259290 ,對(duì)象指針地址:0x7f86bae0d3d8 ,對(duì)象的值:hello,I changed

結(jié)論:不論是用strong還是copy修飾的對(duì)象,其指針指向的地址依然還是originStr的地址蛆橡。
疑問(wèn):為什么_copyyStr的值會(huì)變成“hello,I changed”呢舌界?不應(yīng)該是“hello,originStr”嗎航罗?繼續(xù)往下看
NSMutableString場(chǎng)景二
// 第二種場(chǎng)景:用NSMutableString直接賦值
NSMutableString *originStr = [NSMutableString stringWithFormat:@"hello,originStr"];

self.strongStr = originStr;
self.copyyStr = originStr;

[originStr setString:@"hello,I changed"];

NSLog(@"originStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", originStr, &originStr, originStr);
NSLog(@"strongStr 對(duì)象地址: %p ,對(duì)象指針地址: %p ,對(duì)象的值:%@", _strongStr, &_strongStr, _strongStr);
NSLog(@"copyyStr 對(duì)象地址: %p ,對(duì)象指針地址:%p ,對(duì)象的值:%@", _copyyStr, &_copyyStr, _copyyStr);

控制臺(tái)輸出
2018-09-06 09:23:02.871307+0800 PropertyDemo[2707:246046] originStr 對(duì)象地址: 0x60000024f630 ,對(duì)象指針地址:0x7ffee00bca28 ,對(duì)象的值:hello,I changed
2018-09-06 09:23:02.871465+0800 PropertyDemo[2707:246046] strongStr 對(duì)象地址: 0x60000024f630 ,對(duì)象指針地址: 0x7fb9cf40ea90 ,對(duì)象的值:hello,I changed
2018-09-06 09:23:02.871570+0800 PropertyDemo[2707:246046] copyyStr 對(duì)象地址: 0x60000024fcc0 ,對(duì)象指針地址:0x7fb9cf40ea98 ,對(duì)象的值:hello,originStr

疑問(wèn):self.copyyStr值:hello,originStr 終于是我們想要的結(jié)果
_copyyStr = originStr;和self.copyyStr = originStr;有什么區(qū)別禀横?
原因:
用@property來(lái)聲明屬性變量時(shí),編譯器會(huì)自動(dòng)為我們生成一個(gè)以下劃線加屬性名命名的實(shí)例變量(@synthesize copyyStr = _copyyStr)粥血,并且生成其對(duì)應(yīng)的getter、setter方法酿箭。
1.self.copyyStr = originStr賦值時(shí)复亏,會(huì)調(diào)用coppyStr的setter方法
2._copyyStr = originStr 賦值時(shí)給_copyyStr實(shí)例變量直接賦值,并不會(huì)調(diào)用copyyStr的setter方法
而在setter方法中有一個(gè)非常關(guān)鍵的語(yǔ)句:
_copyyStr = [copyyStr copy];

結(jié)論:
使用self.copyyStr = originStr 賦值時(shí)缭嫡,調(diào)用copyyStr的setter方法缔御,setter方法對(duì)傳入的copyyStr做了次深拷貝生成了一個(gè)新的對(duì)象賦值給_copyyStr,所以_copyyStr指向的地址和對(duì)象值都不再和originStr相同妇蛀。
總結(jié)
由上面的例子可以得出:
1.當(dāng)原字符串是NSString時(shí)耕突,由于是不可變字符串,所以评架,不管使用strong還是copy修飾眷茁,都是指向原來(lái)的對(duì)象,copy操作只是做了一次淺拷貝纵诞。
2.當(dāng)源字符串是NSMutableString時(shí)上祈,strong只是將源字符串的引用計(jì)數(shù)加1,而copy則是對(duì)原字符串做了次深拷貝浙芙,從而生成了一個(gè)新的對(duì)象登刺,并且copy的對(duì)象指向這個(gè)新對(duì)象。
所以嗡呼,如果源字符串是NSMutableString的時(shí)候纸俭,使用strong只會(huì)增加引用計(jì)數(shù)。但是copy會(huì)執(zhí)行一次深拷貝南窗,會(huì)造成不必要的內(nèi)存浪費(fèi)揍很。而如果原字符串是NSString時(shí)廊宪,strong和copy效果一樣,就不會(huì)有這個(gè)問(wèn)題女轿。
但是箭启,我們一般聲明NSString時(shí),也不希望它改變蛉迹,所以一般情況下傅寡,建議使用copy,這樣可以避免NSMutableString帶來(lái)的錯(cuò)誤北救。

隨便補(bǔ)充幾個(gè)知識(shí)點(diǎn):
簡(jiǎn)要闡述內(nèi)存相關(guān)的關(guān)鍵字荐操?
Strong:
指向并持有該對(duì)象,引用計(jì)數(shù)會(huì)加1珍策。引用計(jì)數(shù)為0銷(xiāo)毀托启,可以通過(guò)將變量強(qiáng)制賦值 nil 來(lái)進(jìn)行銷(xiāo)毀。
Weak:
指向但是并不持有該對(duì)象攘宙,引用計(jì)數(shù)不會(huì)加1屯耸。在 Runtime 中對(duì)該屬性進(jìn)行了相關(guān)操作,無(wú)需處理蹭劈,可以自動(dòng)銷(xiāo)毀
assign:
assign主要用于修飾基本數(shù)據(jù)類(lèi)型疗绣,例如NSInteger,CGFloat铺韧,存儲(chǔ)在棧中多矮,內(nèi)存不用程序員管理
copy:
copy關(guān)鍵字和 strong類(lèi)似,copy 多用于修飾有可變類(lèi)型的不可變對(duì)象上 NSString,NSArray,NSDictionary上哈打。
__unsafe_unretain:
__unsafe_unretain 類(lèi)似于 weak 塔逃,但是當(dāng)對(duì)象被釋放后,指針依然保存著之前的地址料仗,被釋放后的地址變?yōu)?僵尸對(duì)象湾盗,訪問(wèn)被釋放的地址就會(huì)出問(wèn)題,所以說(shuō)他是不安全的罢维。
atomic:
這個(gè)屬性是為了保證在多線程的情況下淹仑,編譯器會(huì)自動(dòng)生成一些互斥加鎖的代碼,避免該變量的讀寫(xiě)不同步的問(wèn)題肺孵。
nonatomic :
如果該對(duì)象無(wú)需考慮多線程的情況匀借,這個(gè)屬性會(huì)讓編譯器少生成一些互斥代碼,可以提高效率平窘。
__weak 和 __unsafe_unretain 的區(qū)別吓肋?
__unsafe_unretain 在指向的內(nèi)存地址銷(xiāo)毀后,指針本身并不會(huì)自動(dòng)銷(xiāo)毀瑰艘,這也就造成了野指針是鬼,之后容易造成 Crash肤舞。__weak 在指向的內(nèi)存銷(xiāo)毀后,可以將指針變量置為 nil均蜜,這樣更加安全李剖。
__weak 修飾的變量在地址被釋放后,為何被置為 nil囤耳?
在 Runtime 中專(zhuān)門(mén)維護(hù)了一個(gè)用于存儲(chǔ) weak指針變量的 Hash 表篙顺。這個(gè)表 key 是 weak指針?biāo)赶虻膬?nèi)存地址,value 是指向這個(gè)內(nèi)存地址的所有 weak指針充择,實(shí)際上是一個(gè)數(shù)組德玫。釋放時(shí)根據(jù)對(duì)象地址獲取所有 weak指針 地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為 nil椎麦,最后把這個(gè) 對(duì)象 從weak表 中刪除宰僧。
使用atomic一定是線程安全的嗎?
atomic可以保證setter和getter存取的線程安全并不保證整個(gè)對(duì)象是線程安全的观挎。
比如琴儿,聲明一個(gè)NSMutableArray的原子屬性array,此時(shí)self.array和self.array = otherArray都是線程安全的键兜。但是凤类,使用[self.array objectAtIndex:index]就不是線程安全的,需要用鎖來(lái)保證線程安全性普气。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市佃延,隨后出現(xiàn)的幾起案子现诀,更是在濱河造成了極大的恐慌,老刑警劉巖履肃,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仔沿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡尺棋,警方通過(guò)查閱死者的電腦和手機(jī)封锉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)膘螟,“玉大人成福,你說(shuō)我怎么就攤上這事【2校” “怎么了奴艾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)内斯。 經(jīng)常有香客問(wèn)我蕴潦,道長(zhǎng)像啼,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任潭苞,我火速辦了婚禮忽冻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘此疹。我一直安慰自己僧诚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布秀菱。 她就那樣靜靜地躺著振诬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衍菱。 梳的紋絲不亂的頭發(fā)上赶么,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音脊串,去河邊找鬼辫呻。 笑死,一個(gè)胖子當(dāng)著我的面吹牛琼锋,可吹牛的內(nèi)容都是我干的放闺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缕坎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怖侦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起谜叹,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤匾寝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后荷腊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體艳悔,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年女仰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猜年。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疾忍,死狀恐怖乔外,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锭碳,我是刑警寧澤袁稽,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站擒抛,受9級(jí)特大地震影響推汽,放射性物質(zhì)發(fā)生泄漏补疑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一歹撒、第九天 我趴在偏房一處隱蔽的房頂上張望莲组。 院中可真熱鬧,春花似錦暖夭、人聲如沸锹杈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)竭望。三九已至,卻和暖如春裕菠,著一層夾襖步出監(jiān)牢的瞬間咬清,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工奴潘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旧烧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓画髓,卻偏偏與公主長(zhǎng)得像掘剪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子奈虾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 首先聲明了兩個(gè)NSString屬性夺谁,如下: 下面我們分別以NSString和NSMutableString舉例 N...
    趙哥窟閱讀 8,530評(píng)論 2 20
  • 在iOS開(kāi)發(fā)中,幾乎每天都會(huì)遇到NSString屬性的聲明肉微, 在ARC內(nèi)存管理機(jī)制下予权, NSString屬性聲明有...
    iOS程序媛ing閱讀 201評(píng)論 0 0
  • 第一種場(chǎng)景:用NSString直接賦值 // 第一種場(chǎng)景:用NSString直接賦值 NSString *orig...
    戀空K閱讀 2,062評(píng)論 0 6
  • 級(jí)別: ★☆☆☆☆標(biāo)簽:「iOS」「NSString」「strong和copy」作者: MrLiuQ審校: QiS...
    QiShare閱讀 10,736評(píng)論 17 52
  • 在iOS開(kāi)發(fā)中,幾乎每天都會(huì)遇到NSString屬性的聲明浪册,在ARC內(nèi)存管理機(jī)制下,NSString屬性聲明有兩個(gè)...
    齊舞647閱讀 496評(píng)論 0 10