copy修飾NSArray strong修飾NSMutableArray

陰差陽(yáng)錯(cuò)载弄,前兩天和一個(gè)小伙伴在一起聊天。聊到關(guān)于copy和strong的問(wèn)題叫榕。這個(gè)在ARC[Automatic Reference Counting)]下慢慢淡化的一個(gè)東東熄赡。交流之中讓我受益匪淺,原來(lái)copy和strong還可以這么玩兼贸。

以下內(nèi)容在demo中均有體現(xiàn)

1.首先我們先看一下到底出現(xiàn)了什么問(wèn)題

使用copy修飾這個(gè)可變數(shù)組

@property (copy, nonatomic) NSMutableArray *copAry;

// 直接崩潰測(cè)試- (void)testCash {? ? NSMutableArray *arr = [NSMutableArray arrayWithObjects:@1, @2, @3, nil];self.copAry = arr;? ? [self.copAry removeObject:@1];// 直接崩潰NSLog(@"self.copyAry = %@",self.copAry);}報(bào)錯(cuò)reason:'-[__NSArrayI removeObject:]: unrecognized selector sent to instance 0x6000000487c0'

那么為什么使用strong來(lái)修飾就不會(huì)有這個(gè)問(wèn)題呢段直。

我們來(lái)看一個(gè)例子:

定義一個(gè)CJPerson類,.m 中先不實(shí)現(xiàn)setterr方法

CJPerson.h

在控制器看一下打印結(jié)果

NSMutableArray*names = [@[@"zhangsan"] mutableCopy];? ? CJPerson *person = [[CJPerson alloc] init];? ? person.sAry = names;// strongperson.cAry = names;// copy[names addObject:@"lisi"];NSLog(@"sAry = %@, cAry = %@", person.sAry, person.cAry);/* 輸出結(jié)果:

? ? sAry = (

? ? ? ? zhangsan,

? ? ? ? lisi

? ? ), cAry = (

? ? ? ? zhangsan

? ? )

? ? */

歸根結(jié)底之所以出現(xiàn)這樣問(wèn)題溶诞,那是因?yàn)锳RC情況下strong和copy對(duì)屬性setter方法重寫的區(qū)別鸯檬。

strong:setter時(shí)調(diào)用了[sAry retain]方法,實(shí)現(xiàn)了指針拷貝螺垢,也就是淺拷貝喧务。

copy:setter時(shí)調(diào)用了[cAry copy]方法,實(shí)現(xiàn)了內(nèi)容拷貝甩苛,也就是深拷貝蹂楣。

也就是在 .m 文件中系統(tǒng)默認(rèn)幫我們實(shí)現(xiàn)的是:

CJPerson.m

具體可以看內(nèi)存地址圖詳解:(簡(jiǎn)單粗糙,歡迎大神指正)

內(nèi)存地址分析.png

2.那么這個(gè)與copy修飾NSMutableArray導(dǎo)致崩潰有什么關(guān)系呢讯蒲?

原來(lái)不管是集合類對(duì)象(NSArray,NSDictionary,NSSet...)痊土,還是非集合類對(duì)象(NSString),接收到copy或者mutableCopy消息時(shí),都需遵循以下準(zhǔn)則:

copy返回的都是不可變對(duì)象墨林,所以如果對(duì)copy返回值去調(diào)用可變對(duì)象的接口就會(huì) crash

mutableCopy 返回的都是可變對(duì)象

所以在- (void)testCash方法中執(zhí)行到self.copAry = arr;ARC 環(huán)境下setter方法執(zhí)行了copy方法赁酝,導(dǎo)致原本NSMutableArray類型數(shù)組變成NSArray類型犯祠,在調(diào)用removeObject:方法時(shí),自然會(huì)出現(xiàn)這個(gè)錯(cuò)誤reason: '-[__NSArrayI removeObject:]: unrecognized selector sent to instance 0x6000000487c0'

3.那么NSArray類型為什么需要使用copy來(lái)修飾

我們繼續(xù)使用copy和strong來(lái)定義變量

@property(strong,nonatomic)NSArray*arr1;@property(copy,nonatomic)NSArray*arr2;

// 為什么 NSArray 需要使用 copy- (void)testUserCopyWithAry {NSMutableArray*arr = [NSMutableArrayarrayWithObjects:@(1), @(2), @(3),nil];self.arr1 = arr;self.arr2 = arr;? ? ? ? [arr addObject:@(4)];NSLog(@"arr1 = %@, arr2 = %@",self.arr1,self.arr2);/* 輸出結(jié)果:

? ? arr1 = (

? ? ? ? 1,

? ? ? ? 2,

? ? ? ? 3,

? ? ? ? 4

? ? ), arr2 = (

? ? ? ? 1,

? ? ? ? 2,

? ? ? ? 3

? ? )

? ? */}

簡(jiǎn)直白的說(shuō)就是:如果定義一個(gè)數(shù)組酌呆,使用strong來(lái)修飾的話衡载,如果這個(gè)數(shù)組在外界被修改的話,那么這個(gè)用strong修改的數(shù)組變量的值也會(huì)跟著變化隙袁。為什么痰娱?還是因?yàn)閟trong進(jìn)行了指針拷貝。在內(nèi)存中菩收,兩個(gè)變量指向的是同一塊內(nèi)存地址梨睁。所以為了避免值在外接發(fā)生改變而影響自身值的變化,我們通常選擇使用copy進(jìn)行修飾娜饵。

4.接著再上兩個(gè)測(cè)試?yán)悠潞兀瑢?duì)比看輸出結(jié)果

- (void)test01 {NSArray*array = @[@1,@2,@3,@4];NSArray*copyArr = [arraycopy];NSArray*mCopyArr = [array mutableCopy];NSMutableArray*mcArr = [arraycopy];NSMutableArray*mmCopyArr = [array mutableCopy];NSLog(@"array:%p--copyArr:%p--mCopyArr:%p--mcArr:%p---mmCopyArr:%p",array,copyArr,mCopyArr,mcArr,mmCopyArr);/*? 輸出結(jié)果

? ? array:? ? 0x60000024ce10

? ? copyArr:? 0x60000024ce10

? ? mCopyArr:? 0x60000024cd80

? ? mcArr:? ? 0x60000024ce10

? ? mmCopyArr: 0x60000024ce70

? ? */}- (void)test02 {NSArray*tarray = @[@1,@2,@3,@4];NSMutableArray*array = [[NSMutableArrayalloc] init];? ? [array addObjectsFromArray:tarray];NSArray*copyArr = [arraycopy];NSArray*mCopyArr = [array mutableCopy];NSMutableArray*mcArr = [arraycopy];NSMutableArray*mmCopyArr = [array mutableCopy];NSLog(@"array:%p--copyArr:%p--mCopyArr:%p--mcArr:%p---mmCopyArr:%p",array,copyArr,mCopyArr,mcArr,mmCopyArr);/* 輸出結(jié)果

? ? array:? ? 0x60000024cd20

? ? copyArr:? 0x60000024cc90

? ? mCopyArr:? 0x60000024ce40

? ? mcArr:? ? 0x60000024cde0

? ? mmCopyArr: 0x60000024d020

? ? */}

小結(jié)一下:

NSArray的copy ---->指針拷貝---->淺拷貝

NSArray的mutableCopy,NSMutableArray的copy, NSMutableArray的mutableCopy 均為深拷貝箱舞,即內(nèi)容拷貝遍坟。

關(guān)于NSString(非集合類對(duì)象),NSDictionary及其對(duì)應(yīng)的可變類型都可以此類推。

5.淺拷貝晴股、深拷貝

全篇在講淺拷貝愿伴、深拷貝,追究他們追究到底是什么队魏。

段子手的理解:淺復(fù)制好比你和你的影子公般,你完蛋,你的影子也完蛋胡桨。深復(fù)制好比你和你的克隆人官帘,你完蛋,你的克隆人還活著昧谊。

淺拷貝

淺拷貝就是對(duì)內(nèi)存地址的復(fù)制刽虹,目標(biāo)對(duì)象和原對(duì)象指向同一片內(nèi)存地址。

注意

多個(gè)對(duì)象共用一塊地址時(shí)呢诬,當(dāng)內(nèi)存銷毀的時(shí)候涌哲,指向這片內(nèi)存地址的幾個(gè)指針需要重新定義才可以使用,否則出現(xiàn)野指針現(xiàn)象尚镰。

iOS的淺拷貝中阀圾,通常會(huì)使用retain關(guān)鍵字進(jìn)行引用計(jì)數(shù)。因?yàn)樗瓤梢宰寧讉€(gè)指針共同指向同一內(nèi)存地址狗唉,也可以在release的時(shí)候 由于計(jì)數(shù)的存在初烘,不會(huì)讓內(nèi)存銷毀,從而出現(xiàn)野指針的現(xiàn)象。

深拷貝

深拷貝也就是內(nèi)容拷貝肾筐。目標(biāo)對(duì)象雖然和原對(duì)象的值一樣哆料,但是所指向的內(nèi)存地址不一樣÷痤恚可以說(shuō)深拷貝把原對(duì)象地址也拷貝了东亦,而內(nèi)存地址是自主分配的。因內(nèi)存地址不一樣唬渗,兩個(gè)對(duì)象也就互不影響典阵、互不干涉了。

iOS的深拷貝中谣妻,通常會(huì)使用copy和mutableCopy方法

// 深拷貝- (void)testDeepCopy {NSString*str =@"abcdefg";NSString*cStr = [strcopy];NSMutableString*mStr = [str mutableCopy];? ? [mStr appendString:@"!!"];NSLog(@"\n str = %@ = %p,\n cStr = %@ = %p,\n mStr = %@ = %p", str, str, cStr, cStr, mStr, mStr);}/* 輸出結(jié)果:

str = abcdefg = 0x109dd8090,

cStr = abcdefg = 0x109dd8090,

mStr = abcdefg!! = 0x604000057e50

*/

再次驗(yàn)證了第 4 個(gè)模塊

番外篇

淺拷貝的retain和 深拷貝中提到的copy有什么區(qū)別呢

可以觀看這篇文章:copy 和 retain 到底有啥區(qū)別

6.拷貝構(gòu)造

當(dāng)然在iOS中并不是所有的對(duì)象都支持copy萄喳,mutableCopy卒稳,遵守NSCopying協(xié)議的類可以發(fā)送copy消息蹋半,遵守NSMutableCopying協(xié)議的類才可以發(fā)送mutableCopy消息。

假如發(fā)送了一個(gè)沒有遵守上訴兩協(xié)議而發(fā)送copy或者mutableCopy, 那么就會(huì)發(fā)生異常充坑。但是默認(rèn)的iOS類并沒有遵守這兩個(gè)協(xié)議减江。如果想自定義一下copy那么就必須遵守NSCopying, 并且實(shí)現(xiàn)copyWithZone:方法,如果想自定義一下mutableCopy那么就必須遵守NSMutableCopying, 并且實(shí)現(xiàn)mutableCopyWithZone:方法捻爷。

自定義 model辈灼,遵守NSCopying和NSMutableCopying協(xié)議

@interfaceCJObj:NSObject@property(copy,nonatomic)NSString*name;@property(copy,nonatomic)NSString*icon;@end

實(shí)現(xiàn):

CJObj.m

在ViewController中打印結(jié)果

// 拷貝構(gòu)造- (void)copyConstruct {? ? CJObj *obj = [[CJObj alloc] init];? ? obj.name =@"zhangsan";? ? obj.icon =@"icon";NSMutableArray*arr = [NSMutableArrayarray];NSMutableArray*copyAry = [NSMutableArrayarray];? ? [arr addObject:obj];? ? ? ? [copyAry addObject:[arr[0]copy]];//[copyAry addObject:[arr[0] mutableCopy]];CJObj *obj2 = arr[0];? ? obj2.name =@"lisi";? ? obj2.icon =@"obj2_icon";NSLog(@"arr.name = %@, arr.icon = %@", ((CJObj *)arr[0]).name, ((CJObj *)arr[0]).icon);NSLog(@"copyArr.name = %@, copyArr.icon = %@", ((CJObj *)[copyAry objectAtIndex:0]).name, ((CJObj *)[copyAry objectAtIndex:0]).icon);/* 輸出結(jié)果:

? ? ? ? arr.name = lisi, arr.icon = obj2_icon

? ? ? ? copyArr.name = zhangsan, copyArr.icon = icon

? ? */}

內(nèi)存地址圖詳解:(簡(jiǎn)單粗糙,歡迎大神指正)

拷貝構(gòu)造

以上內(nèi)容在demo中均有體現(xiàn)

感謝:

本文第3也榄、4模塊出自這里

淺拷貝巡莹、深拷貝

拷貝構(gòu)造部分

相關(guān)閱讀:

什么是ARC

作者:笨笨編程

鏈接:http://www.reibang.com/p/2008e585c1a0

來(lái)源:簡(jiǎn)書

簡(jiǎn)書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處甜紫。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末降宅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子囚霸,更是在濱河造成了極大的恐慌腰根,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拓型,死亡現(xiàn)場(chǎng)離奇詭異额嘿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)劣挫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門册养,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人压固,你說(shuō)我怎么就攤上這事球拦。” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵刘莹,是天一觀的道長(zhǎng)阎毅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)点弯,這世上最難降的妖魔是什么扇调? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮抢肛,結(jié)果婚禮上狼钮,老公的妹妹穿的比我還像新娘。我一直安慰自己捡絮,他們只是感情好熬芜,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著福稳,像睡著了一般涎拉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上的圆,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天鼓拧,我揣著相機(jī)與錄音,去河邊找鬼越妈。 笑死季俩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的梅掠。 我是一名探鬼主播酌住,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼阎抒!你這毒婦竟也來(lái)了酪我?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤挠蛉,失蹤者是張志新(化名)和其女友劉穎祭示,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谴古,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡质涛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了掰担。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汇陆。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖带饱,靈堂內(nèi)的尸體忽然破棺而出毡代,到底是詐尸還是另有隱情阅羹,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布教寂,位于F島的核電站捏鱼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏酪耕。R本人自食惡果不足惜导梆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迂烁。 院中可真熱鬧看尼,春花似錦、人聲如沸盟步。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)却盘。三九已至狰域,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谷炸,已是汗流浹背北专。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旬陡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓语婴,卻偏偏與公主長(zhǎng)得像描孟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子砰左,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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