Copy與MutabCopy

先說結果下面會一一測試

比對copy與mutable比對

1.NSString、NSMutableString、NSArray、NSMutableArray ->copy與mutablecopy

? ? //1不可變字符串

//? ? NSMutableString *string = [NSMutableString stringWithString:@"test"];

//? ? NSString *str = [NSString stringWithString:string];

//? ? NSString *str2 = [str copy];

//? ? NSMutableString *str3 = [str mutableCopy];

//? ? NSLog(@"原始值 --%p---%@--",str,str);

//? ? NSLog(@"copy值 --%p---%@--",str2,str2);

//? ? NSLog(@"mutableCopy值 --%p---%@--",str3,str3);

//? ? [string appendString:@"aaa"];

//? ? [str3 appendString:@"bbbbb"];

//? ? NSLog(@"原始值 --%p---%@--",str,str);

//? ? NSLog(@"copy值 --%p---%@--",str2,str2);

//? ? NSLog(@"mutableCopy值 --%p---%@--",str3,str3);

? ? /*


?? ? 2019-11-11 14:43:35.696 YJApiRequestTool[14269:251156] 原始值 --0xa000000747365744---test--

?? ? 2019-11-11 14:43:35.696 YJApiRequestTool[14269:251156] copy值 --0xa000000747365744---test--

?? ? 2019-11-11 14:43:35.696 YJApiRequestTool[14269:251156] mutableCopy值 --0x7fcd34c0d770---test--

?? ? 2019-11-11 14:43:35.696 YJApiRequestTool[14269:251156] 原始值 --0xa000000747365744---test--

?? ? 2019-11-11 14:43:35.696 YJApiRequestTool[14269:251156] copy值 --0xa000000747365744---test--

?? ? 2019-11-11 14:43:35.697 YJApiRequestTool[14269:251156] mutableCopy值 --0x7fcd34c0d770---testbbbbb--


?? ? 原始值與copy出來的值一樣 一直沒有改變 地址也一樣

?? ? mutableCopy 地址不一樣 值改變不影響原始值

?? ? */


? ? //2 可變字符串

//? ? NSMutableString * mutableStr = [[NSMutableString alloc]initWithString:string];

//? ? NSString*mutableStr2 = [mutableStr copy];

//? ? NSMutableString*mutableStr3 = [mutableStr mutableCopy];

//? ? ? ? NSLog(@"原始值 --%p---%@--",mutableStr,mutableStr);

//? ? ? ? NSLog(@"copy值 --%p---%@--",mutableStr2,mutableStr2);

//? ? ? ? NSLog(@"mutableCopy值 --%p---%@--",mutableStr3,mutableStr3);

//? ? ? ? [string appendString:@"aaa"];

//? ? ? ? [mutableStr appendString:@"bbbbb"];

//? ? ? ? [mutableStr3 appendString:@"ccccccc"];

//? ? ? ? NSLog(@"原始值 --%p---%@--",mutableStr,mutableStr);

//? ? ? ? NSLog(@"copy值 --%p---%@--",mutableStr2,mutableStr2);

//? ? ? ? NSLog(@"mutableCopy值 --%p---%@--",mutableStr3,mutableStr3);


? ? /*


?? ? 2019-11-11 14:58:27.749 YJApiRequestTool[14636:263259] 原始值 --0x7fee622381d0---test--

?? ? 2019-11-11 14:58:27.750 YJApiRequestTool[14636:263259] copy值 --0xa000000747365744---test--

?? ? 2019-11-11 14:58:27.750 YJApiRequestTool[14636:263259] mutableCopy值 --0x7fee6223a0d0---test--

?? ? 2019-11-11 14:58:27.750 YJApiRequestTool[14636:263259] 原始值 --0x7fee622381d0---testbbbbb--

?? ? 2019-11-11 14:58:27.750 YJApiRequestTool[14636:263259] copy值 --0xa000000747365744---test--

?? ? 2019-11-11 14:58:27.751 YJApiRequestTool[14636:263259] mutableCopy值 --0x7fee6223a0d0---testccccccc--


?? ? 可變字符串,copy,mutableCopy 都會將整個對象重新拷貝

?? ? */


//? ? NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2", nil];

//? ? NSArray *originArr = [NSArray arrayWithObject:array];

//? ? NSArray *copyArr = [originArr copy];

//? ? NSMutableArray *mutableArr = [originArr mutableCopy];

//

//? ? NSLog(@"原始數(shù)組%p? ? %@",originArr,originArr);

//? ? NSLog(@"Copy數(shù)組%p? ? %@",copyArr,copyArr);

//? ? NSLog(@"MutableCopy數(shù)組%p? ? %@",mutableArr,mutableArr);

//

//? ? [array addObject:@"3"];

//? ? [mutableArr addObject:@"4"];

//

//? ? NSLog(@"修改數(shù)組%p? ? %@",originArr,originArr);

//? ? NSLog(@"修改Copy數(shù)組%p? ? %@",copyArr,copyArr);

//? ? NSLog(@"修改MutableCopy數(shù)組%p? ? %@",mutableArr,mutableArr);

? ? /*

?? ? 2019-11-11 15:19:42.079 YJApiRequestTool[15114:277864] 原始數(shù)組0x7faba8507530? ? (

?? ? (

?? ? 1,

?? ? 2

?? ? )

?? ? )

?? ? 2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] Copy數(shù)組0x7faba8507530? ? (

?? ? (

?? ? 1,

?? ? 2

?? ? )

?? ? )

?? ? 2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] MutableCopy數(shù)組0x7faba850ad00? ? (

?? ? (

?? ? 1,

?? ? 2

?? ? )

?? ? )

?? ? 2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] 修改數(shù)組0x7faba8507530? ? (

?? ? (

?? ? 1,

?? ? 2,

?? ? 3

?? ? )

?? ? )

?? ? 2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] 修改Copy數(shù)組0x7faba8507530? ? (

?? ? (

?? ? 1,

?? ? 2,

?? ? 3

?? ? )

?? ? )

?? ? 2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] 修改MutableCopy數(shù)組0x7faba850ad00? ? (

?? ? (

?? ? 1,

?? ? 2,

?? ? 3

?? ? ),

?? ? 4

?? ? )


?? ? copy 指針拷貝 指向的是同一塊內存地址

?? ? MutableCopy 是對象拷貝一份 修改值后 不影響之前的值

?? ? 這里或許有個疑問 originArr 為什么會是[(1,2,3)];這個其實很容易理解的 那是因為 指針指向的這塊內存區(qū)域值發(fā)生了改變 所以才是[(1,2,3)]

?? ? 因此: 數(shù)組復制,其元素對象始終是指針復制,元素指向的值改變,數(shù)組自然都會改變。

?? ? */


//? ? ? ? NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2", nil];

//? ? ? ? NSMutableArray *originArr = [NSMutableArray arrayWithArray:array];

//? ? ? ? NSArray *copyArr = [originArr copy];

//? ? ? ? NSMutableArray *mutableArr = [originArr mutableCopy];

//

//? ? ? ? NSLog(@"原始數(shù)組%p? ? %@",originArr,originArr);

//? ? ? ? NSLog(@"Copy數(shù)組%p? ? %@",copyArr,copyArr);

//? ? ? ? NSLog(@"MutableCopy數(shù)組%p? ? %@",mutableArr,mutableArr);

//

//? ? ? ? [array addObject:@"3"];

//? ? ? ? [originArr addObject:@"5"];

//? ? ? ? [mutableArr addObject:@"4"];

//

//? ? ? ? NSLog(@"修改數(shù)組%p? ? %@",originArr,originArr);

//? ? ? ? NSLog(@"修改Copy數(shù)組%p? ? %@",copyArr,copyArr);

//? ? ? ? NSLog(@"修改MutableCopy數(shù)組%p? ? %@",mutableArr,mutableArr);

? ? /*

?? ? 2019-11-11 15:26:05.199 YJApiRequestTool[15278:283199] 原始數(shù)組0x7fbcdd61b7c0? ? (

?? ? 1,

?? ? 2

?? ? )

?? ? 2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] Copy數(shù)組0x7fbcdd61e090? ? (

?? ? 1,

?? ? 2

?? ? )

?? ? 2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] MutableCopy數(shù)組0x7fbcdd61d480? ? (

?? ? 1,

?? ? 2

?? ? )

?? ? 2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] 修改數(shù)組0x7fbcdd61b7c0? ? (

?? ? 1,

?? ? 2,

?? ? 5

?? ? )

?? ? 2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] 修改Copy數(shù)組0x7fbcdd61e090? ? (

?? ? 1,

?? ? 2

?? ? )

?? ? 2019-11-11 15:26:05.201 YJApiRequestTool[15278:283199] 修改MutableCopy數(shù)組0x7fbcdd61d480? ? (

?? ? 1,

?? ? 2,

?? ? 4

?? ? )


?? ? 對于可變數(shù)組,可以看到不管哪種copy,都會對對象重新拷貝 改變各自的值 互不影響


?? ? */


2、自定義對象的復制

使用copy和mutableCopy復制對象的副本使用起來確實方便,那么我們自定義的類是否可調用copy與mutableCopy方法來復制副本呢?先定義一個Person類,代碼如下:

@interfacePerson:NSObject

@property(nonatomic,assign)NSIntegerage;

@property(nonatomic,copy)NSString *name;

@end

然后嘗試調用Person的copy方法來復制一個副本:

Person *person1=[[Personalloc]init];//創(chuàng)建一個Person對象

person1.age=20;

person1.name=@"張三";

Person *person2=[person1copy];//復制副本

運行程序,將會發(fā)生崩潰,并輸出以下錯誤信息:

[PersoncopyWithZone:]:unrecognized selector senttoinstance0x608000030920

上面的提示:Person找不到copyWithZone:方法。我們將復制副本的代碼換成如下:

Person *person2=[person1mutableCopy];//復制副本

再次運行程序,程序同樣崩潰了,并輸出去以下錯誤信息:

[PersonmutableCopyWithZone:]:unrecognized selector senttoinstance0x600000221120

上面的提示:Person找不到mutableCopyWithZone:方法。

大家可能會覺得疑惑,程序只是調用了copy和mutableCopy方法,為什么會提示找不到copyWithZone:與mutableCopyWithZone:方法呢?其實當程序調用對象的copy方法來復制自身時,底層需要調用copyWithZone:方法來完成實際的復制工作,copy返回實際上就是copyWithZone:方法的返回值;mutableCopy與mutableCopyWithZone:方法也是同樣的道理。

那么怎么做才能讓自定義的對象進行copy與mutableCopy呢?需要做以下事情:

1.讓類實現(xiàn)NSCopying/NSMutableCopying協(xié)議。

2.讓類實現(xiàn)copyWithZone:/mutableCopyWithZone:方法

所以讓我們的Person類能夠復制自身,我們需要讓Person實現(xiàn)NSCopying協(xié)議;然后實現(xiàn)copyWithZone:方法:

@interfacePerson:NSObject

@property(nonatomic,assign)NSIntegerage;

@property(nonatomic,copy)NSString *name;

@end

#import "Person.h"

@implementationPerson

-(id)copyWithZone:(NSZone *)zone{

Person *person=[[[selfclass]allocWithZone:zone]init];

person.age=self.age;

person.name=self.name;

returnperson;

}

@end

運行之后發(fā)現(xiàn)我們實現(xiàn)了對象的復制:

同時需要注意的是如果對象中有其他指針類型的實例變量,且只是簡單的賦值操作:person.obj2 = self.obj2,其中obj2是另一個自定義類,如果我們修改obj2中的屬性,我們會發(fā)現(xiàn)復制后的person對象中obj2對象中的屬性值也變了,因為對于這個對象并沒有進行copy操作,這樣的復制操作不是完全的復制,如果要實現(xiàn)完全的復制,需要將obj2對應的類也要實現(xiàn)copy,然后這樣賦值:person.obj2 = [self.obj2 copy]。如果對象很多或者層級很多,實現(xiàn)起來還是很麻煩的。如果需要實現(xiàn)完全復制同樣還有另有一種方法,那就是歸檔:

Person *person2=[NSKeyedUnarchiverunarchiveObjectWithData:[NSKeyedArchiverarchivedDataWithRootObject:person1]];

這樣我們就實現(xiàn)了自定義對象的復制,需要指出的是如果重寫copyWithZone:方法時,其父類已經實現(xiàn)NSCopying協(xié)議,并重寫過了copyWithZone:方法,那么子類重寫copyWithZone:方法應先調用父類的copy方法復制從父類繼承得到的成員變量,然后對子類中定義的成員變量進行賦值:

-(id)copyWithZone:(NSZone *)zone{

idobj=[supercopyWithZone:zone];

//對子類定義的成員變量賦值

...

returnobj;

}

關于mutableCopy的實現(xiàn)與copy的實現(xiàn)類似,只是實現(xiàn)的是NSMutableCopying協(xié)議與mutableCopyWithZone:方法。對于自定義的對象,在我看來并沒有什么可變不可變的概念,因此實現(xiàn)mutableCopy其實是沒有什么意義的,在此就不詳細介紹了。

3、定義屬性的copy指示符

如下段代碼,我們在定義屬性的時候使用了copy指示符:

#import

@interfacePerson:NSObject

@property(nonatomic,copy)NSMutableString *name;

@end

使用如下代碼來進行測試:

Person *person1=[[Personalloc]init];//創(chuàng)建一個Person對象

person1.name=[NSMutableStringstringWithString:@"蘇小妖"];

[person1.nameappendString:@"123"];

運行程序會崩潰,并且提示以下信息:

***Terminating app duetouncaughtexception'NSInvalidArgumentException',reason:'Attempt to mutate immutable object with appendString:'

這段錯誤提示不允許修改person的name屬性,這是因為程序定義name屬性時使用了copy指示符,該指示符置頂調用setName:方法時(通過點語法賦值時,實際上是調用對應的setter方法),程序實際上會使用參數(shù)的副本對name實際變量復制。也就是說,setName:方法的代碼如下:

-(void)setName:(NSMutableString *)name{

_name=[namecopy];

}

copy方法默認是復制該對象的不可變副本,雖然程序傳入的NSMutableString,但程序調用該參數(shù)的copy方法得到的是不可變副本。因此,程序賦給Person對象的name實例變量的值依然是不可變字符串。

注意:定義合成getter、setter方法時并沒有提供mutableCopy指示符。因此即使定義實例變量時使用了可變類型,但只要使用copy指示符,實例變量實際得到的值總是不可變對象。

copy與mutableCopy還有一個特點:

修改源對象的屬性和行為,不會影響副本對象

修改副本對象的屬性和行為,不會影響源對象

互不影響

4.block-copy

對于block為什么用copy 你應該就理解了 這里有一個知識點 block默認保存在棧區(qū)

?? ? 棧區(qū)在對外部對象進行操作時,不會對對象進行retain,當block保存在堆區(qū)時,在外部對象進行操作時,會對對象進行retain。而我們本是是不知道什么時候什么時候調用block的,當block中的對象提前釋放,會造成Crash,但這時又回出現(xiàn)循環(huán)引用又該怎么辦

?? ? __weak typeof(self)weakself = self; 即可解決

?? ? 使用__block 來修飾 這會把 棧中的內存地址放到了堆中 如果不使用__block

?? ? 他會出現(xiàn)倆個指針地址

/*

?NSMutableString *mutableStr = [NSMutableString stringWithString:@"1"];

? ? NSLog(@"1--棧中str的地址%p,str指向堆中的地址%p",&mutableStr,mutableStr);

? ? void(^mutableStrBlock)(void) = ^(void){

? ? ? ? mutableStr.string=@"2";

? ? ? ? NSLog(@"2--棧中str的地址%p,str指向堆中的地址%p",&mutableStr,mutableStr);

? ? }; ? ?mutableStrBlock();

*/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容