copy 是淺拷貝状知,mutableCopy 是深拷貝,從我學(xué)習(xí)的時(shí)候開(kāi)始 老師貌似也是這么說(shuō)的孽查,我也一直是這么記的【尷尬】這是不對(duì)的<病!Cぴ佟N魃琛!4鹋蟆4俊!B逃场擒滑!
創(chuàng)建一個(gè)對(duì)象, 該對(duì)象與源對(duì)象的內(nèi)容一致,此時(shí)使用copy與mutableCopy的區(qū)別:
copy拷貝出來(lái)的對(duì)象類型總是不可變類型(例如, NSString, NSDictionary, NSArray等等)
mutableCopy拷貝出來(lái)的對(duì)象類型總是可變類型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
聲明屬性的時(shí)候修飾使用copy修飾的原因:
補(bǔ)充一點(diǎn)堆棧的介紹:
堆和棧是操作系統(tǒng)的內(nèi)存中堆和棧,不是數(shù)據(jù)結(jié)構(gòu)中的堆和棧叉弦。
1丐一、堆(heap)區(qū):堆是由程序員分配和釋放,用于存放進(jìn)程運(yùn)行中被動(dòng)態(tài)分配的內(nèi)存段淹冰,它大小并不固定库车,可動(dòng)態(tài)擴(kuò)張或縮減。當(dāng)進(jìn)程調(diào)用alloc等函數(shù)分配內(nèi)存時(shí)樱拴,新分配的內(nèi)存就被動(dòng)態(tài)添加到堆上(堆被擴(kuò)張)柠衍;當(dāng)利用realse釋放內(nèi)存時(shí),被釋放的內(nèi)存從堆中被剔除(堆被縮減)晶乔,因?yàn)槲覀儸F(xiàn)在iOS基本都使用ARC來(lái)管理對(duì)象珍坊,所以不用我們程序員來(lái)管理,但是我們要知道這個(gè)對(duì)象存儲(chǔ)的位置正罢。
2阵漏、棧(stack)區(qū):棧是由編譯器自動(dòng)分配并釋放默刚,用戶存放程序臨時(shí)創(chuàng)建的局部變量好渠,存放函數(shù)的參數(shù)值,局部變量等拼窥。也就是說(shuō)我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量裆泳,static意味這在數(shù)據(jù)段中存放變量)叹洲。除此以外在函數(shù)被調(diào)用時(shí),其參數(shù)也會(huì)被壓入發(fā)起調(diào)用的進(jìn)程棧中工禾,并且待到調(diào)用結(jié)束后运提,函數(shù)的返回值也回被存放回棧中蝗柔。由于棧的先進(jìn)后出特點(diǎn),所以棧特別方便用來(lái)保存/恢復(fù)調(diào)用現(xiàn)場(chǎng)民泵。從這個(gè)意義上將我們可以把椊朐郏看成一個(gè)臨時(shí)數(shù)據(jù)寄存、交換的內(nèi)存區(qū)洪灯。
- block為什么要用copy?
MRC下不使用copy修飾, block存儲(chǔ)在棧區(qū), 作用域結(jié)束, block這個(gè)局部變量被銷(xiāo)毀, 而一個(gè)strong指針還指向了這個(gè)被回收的地址.所以使用copy,把block拷貝到堆區(qū), 并且指向堆區(qū)的block. 但是在ARC下無(wú)論copy,還是stong都無(wú)所謂, 因?yàn)橄到y(tǒng)已經(jīng)在創(chuàng)建block的時(shí)候, 已經(jīng)拷貝到堆區(qū)了。copy在MRC中是為了保護(hù)block的封裝性將其移動(dòng)至堆區(qū)竟痰。但在ARC中更多的是為了語(yǔ)義化签钩、因?yàn)橄到y(tǒng)自動(dòng)幫你移動(dòng)了
補(bǔ)充個(gè)常用的NSString用copy修飾的原因:
用copy是為了安全,防止NSMutableString賦值給NSString時(shí),前者修改引起后者值變化而用的.這個(gè)也適用于別的下文也會(huì)提到并驗(yàn)證。
@property (nonatomic,strong) NSString *myName;
NSMutableString *mStr = [[NSMutableString alloc] initWithString:@"daLi"];
self.myName = mStr;
NSLog(@"%@", self.myName);
[mStr appendString:@"好美"];
NSLog(@"%@", mStr);
NSLog(@"%@", self.myName);
/*
分析:self.myName聲明的時(shí)候使用strong修飾坏快,會(huì)跟著mStr的改變而改變
輸出:
2017-12-11 16:41:39.146126+0800 Demo[20438:1163039] daLi
2017-12-11 16:41:39.146357+0800 Demo[20438:1163039] daLi好美
2017-12-11 16:41:39.146496+0800 Demo[20438:1163039] daLi好美
*/
@property (nonatomic,copy) NSString *myName;
NSMutableString *mStr = [[NSMutableString alloc] initWithString:@"daLi"];
self.myName = mStr;
NSLog(@"%@", self.myName);
[mStr appendString:@"好美"];
NSLog(@"%@", mStr);
NSLog(@"%@", self.myName);
/*
分析:self.myName聲明的時(shí)候使用copy修飾铅檩,不會(huì)跟著mStr的改變而改變
輸出:
2017-12-11 16:46:08.367018+0800 Demo[20507:1166962] daLi
2017-12-11 16:46:08.367227+0800 Demo[20507:1166962] daLi好美
2017-12-11 16:46:08.367353+0800 Demo[20507:1166962] daLi
*/
淺拷貝和深拷貝的分析
先介紹一下什么是iOS里面的系統(tǒng)容器類:
比如NSArray,NSMutableArray莽鸿,NSDictionary昧旨,NSMutableDictionary....
淺拷貝和深拷貝?祥得?兔沃??级及?英文就是shallow copy和deep copy
- 淺拷貝:正常的拷貝乒疏,生成一個(gè)新的容器,但卻是和原來(lái)的容器共用內(nèi)部的元素饮焦;
- 深拷貝:不僅生成新的容器怕吴,還生成了新的內(nèi)部元素。
稍作總結(jié):淺拷貝復(fù)制容器县踢,深拷貝復(fù)制容器及其內(nèi)部元素
(copy 與 mutableCopy 不等同于淺拷貝與深拷貝)
接下來(lái)用代碼驗(yàn)證這些:
NSMutableArray *mArr = [NSMutableArray arrayWithObject:@1];
NSLog(@"1-%@--%p", mArr, mArr);
NSMutableArray *marr0 = [NSMutableArray arrayWithObject:mArr];
NSLog(@"2-%@--%p--%p", marr0, marr0, marr0[0]);
NSMutableArray *mCopyArr = [marr0 mutableCopy];//替換成copy是一樣的效果
NSLog(@"3-%@--%p--%p", mCopyArr, mCopyArr, mCopyArr[0]);
[mCopyArr[0] addObject:@2];
NSLog(@"4-%@--%p--%p", mCopyArr, mCopyArr, mCopyArr[0]);
NSLog(@"5-%@--%p--%p", marr0, marr0, marr0[0]);
[marr0[0] addObject:@3];
NSLog(@"6-%@--%p--%p", mCopyArr, mCopyArr, mCopyArr[0]);
NSLog(@"7-%@--%p--%p", marr0, marr0, marr0[0]);
/*
修改了mCopyArr的元素转绷,marr0也跟著改變了元素,因?yàn)槎叩脑厥枪灿玫呐鹌。琜marr0 mutableCopy]只拷貝了數(shù)組容器议经,里面的元素并沒(méi)有拷貝,而是和marr0共用的元素,所以marr0[0]丙曙、mCopyArr[0]元素的地址是一個(gè)爸业,無(wú)論修改它們倆哪一個(gè),對(duì)應(yīng)的數(shù)組marr0亏镰、mCopyArr里面的元素都會(huì)跟著改變扯旷。
由此驗(yàn)證出來(lái):容器類的mutableCopy和copy是淺拷貝,只拷貝容器索抓,并不拷貝元素>觥毯炮!
輸出結(jié)果:
2017-12-11 14:41:53.551658+0800 Demo[19619:1091522] 1-(
1
)--0x600000059f50
2017-12-11 14:41:53.551876+0800 Demo[19619:1091522] 2-(
(
1
)
)--0x6000002576a0--0x600000059f50
2017-12-11 14:41:53.552080+0800 Demo[19619:1091522] 3-(
(
1
)
)--0x60000000b9f0--0x600000059f50
2017-12-11 14:41:53.552357+0800 Demo[19619:1091522] 4-(
(
1,
2
)
)--0x60000000b9f0--0x600000059f50
2017-12-11 14:41:53.552545+0800 Demo[19619:1091522] 5-(
(
1,
2
)
)--0x6000002576a0--0x600000059f50
2017-12-11 14:41:53.552687+0800 Demo[19619:1091522] 6-(
(
1,
2,
3
)
)--0x60000000b9f0--0x600000059f50
2017-12-11 14:41:53.552806+0800 Demo[19619:1091522] 7-(
(
1,
2,
3
)
)--0x6000002576a0--0x600000059f50
*/
寫(xiě)一個(gè)NSArray驗(yàn)證一下
NSArray *arr = @[@"1"];
NSLog(@"1-%@--%p", arr, arr);
NSArray *arr0 = arr;
NSLog(@"2-%@--%p", arr0, arr0);
NSArray *arr1 = [arr copy];
NSLog(@"3-%@--%p", arr1, arr1);
NSArray *arr2 = [arr mutableCopy];
NSLog(@"4-%@--%p", arr2, arr2);
arr = @[@"2"];
NSLog(@"5-%@--%p", arr, arr);
NSLog(@"6-%@--%p", arr0, arr0);
NSLog(@"7-%@--%p", arr1, arr1);
NSLog(@"8-%@--%p", arr2, arr2);
/*
分析:
arr初始化指向的是@[@"1"]數(shù)組,
1耸黑、arr0是直接用arr賦值的桃煎,都是指向了@[@"1"],當(dāng)arr = @[@"2"]大刊,arr指向了@[@"2"]這個(gè)數(shù)組为迈,而arr0不變,因?yàn)閍rr0依舊指向的是@[@"1"]缺菌;
2葫辐、arr1,[arr copy]伴郁,使得arr1指向了arr指向的@[@"1"]耿战,后面arr的指向改變并不會(huì)導(dǎo)致arr1的指向改變;
3焊傅、arr2剂陡,[arr mutableCopy],使得arr1指向了arr指向的@[@"1"]狐胎,后面arr的指向改變并不會(huì)導(dǎo)致arr1的指向改變鸭栖;
輸出:
2017-12-11 15:12:21.130514+0800 Demo[19697:1107933] 1-(
1
)--0x600000001c20
2017-12-11 15:12:21.130690+0800 Demo[19697:1107933] 2-(
1
)--0x600000001c20
2017-12-11 15:12:21.130835+0800 Demo[19697:1107933] 3-(
1
)--0x600000001c20
2017-12-11 15:12:21.130994+0800 Demo[19697:1107933] 4-(
1
)--0x604000056770
2017-12-11 15:12:21.131122+0800 Demo[19697:1107933] 5-(
2
)--0x604000002380
2017-12-11 15:12:21.131255+0800 Demo[19697:1107933] 6-(
1
)--0x600000001c20
2017-12-11 15:12:21.131342+0800 Demo[19697:1107933] 7-(
1
)--0x600000001c20
2017-12-11 15:12:21.131431+0800 Demo[19697:1107933] 8-(
1
)--0x604000056770
*/
cpoy 與直接賦值的對(duì)比分析
直接賦值:
NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@"1", nil];
NSLog(@"0-%@--%p", mArr, mArr);
NSArray *arr = mArr;
NSLog(@"1-%@--%p", arr, arr);
[mArr addObject:@"2"];
NSLog(@"2-%@--%p", mArr, mArr);
NSLog(@"3-%@--%p", arr, arr);
/*
分析:使用直接賦值的方式給arr=mArr,可變數(shù)組mArr添加對(duì)象是在賦值之后, 為什么后面添加對(duì)象還會(huì)影響到不可變數(shù)組arr呢?? 原因很簡(jiǎn)單, 因?yàn)镺bjective-C支持多態(tài). 所以表面上arr是NSArray對(duì)象, 其實(shí)骨子里是NSMutableArray對(duì)象.這樣的話將會(huì)對(duì)后期DEBUG增加很大的成本, 可能會(huì)導(dǎo)致莫名其妙的錯(cuò)誤.開(kāi)發(fā)過(guò)程中應(yīng)該注意此類情況
輸出:
2017-12-11 15:46:21.532252+0800 Demo[20106:1129830] 0-(
1
)--0x604000441350
2017-12-11 15:46:21.532407+0800 Demo[20106:1129830] 1-(
1
)--0x604000441350
2017-12-11 15:46:21.532528+0800 Demo[20106:1129830] 2-(
1,
2
)--0x604000441350
2017-12-11 15:46:21.532652+0800 Demo[20106:1129830] 3-(
1,
2
)--0x604000441350
*/
copy/mutableCopy:
NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@"1", nil];
NSLog(@"0-%@--%p", mArr, mArr);
NSArray *arr = [mArr copy];//mutableCopy
NSLog(@"1-%@--%p", arr, arr);
[mArr addObject:@"2"];
NSLog(@"2-%@--%p", mArr, mArr);
NSLog(@"3-%@--%p", arr, arr);
/*
分析:arr使用copy獲取之后顽爹,再次修改mArr不會(huì)造成arr的改變纤泵,保障了arr的安全。
輸出:
2017-12-11 15:51:29.749360+0800 Demo[20137:1133165] 0-(
1
)--0x60000005daf0
2017-12-11 15:51:29.749537+0800 Demo[20137:1133165] 1-(
1
)--0x600000007ec0
2017-12-11 15:51:29.749639+0800 Demo[20137:1133165] 2-(
1,
2
)--0x60000005daf0
2017-12-11 15:51:29.749787+0800 Demo[20137:1133165] 3-(
1
)--0x600000007ec0
*/
然后再寫(xiě)一個(gè)字典的來(lái)驗(yàn)證驗(yàn)證:
NSDictionary *dictA = @{@"a": @"a"};
NSDictionary *dictB = dictA;
dictA = @{@"b": @"b"};
NSLog(@"%@ - %p",dictA, dictA); // {b = b}
NSLog(@"%@ - %p",dictB, dictB); // {a = a}
/*
dictB = dictA, 代表dictA和dictB都指向{@"a" : @"a"},
dictA = @{@"b" : @"b"}這行代碼之后dictA就轉(zhuǎn)而指向@{@"b" : @"b"}了.
而dictA仍然指向{@"a" : @"a"}.
所以輸出:
{
b = b;
} - 0x604000039ae0
{
a = a;
} - 0x604000030180
*/
Person *pA = [[Person alloc] init];
pA.name = @"A1";
Person *pB = [[Person alloc] init];
pB = pA;
pA.name = @"A2";
NSLog(@"%@ - %p - %p", pA.name, pA, &pA);
NSLog(@"%@ - %p - %p", pB.name, pB, &pB);
/*
Person *pB = [[Person alloc] init];這句代碼是沒(méi)有任何作用的, 對(duì)pB后面的指向沒(méi)有任何影響, pB = pA這句代碼過(guò)后, pB和pA指向的是同一個(gè)對(duì)象, 那么通過(guò)pA修改其指向的對(duì)象的name屬性, 自然也會(huì)影響到pB指向的對(duì)象的name屬性. 因?yàn)樗麄儍蓚€(gè)指向的是同一個(gè)對(duì)象
A2 - 0x600000017a50 - 0x7fff5c47cb40
A2 - 0x600000017a50 - 0x7fff5c47cb38
*/