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(@"原始数组%p    %@",originArr,originArr);

//    NSLog(@"Copy数组%p    %@",copyArr,copyArr);

//    NSLog(@"MutableCopy数组%p    %@",mutableArr,mutableArr);

//

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

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

//

//    NSLog(@"修改数组%p    %@",originArr,originArr);

//    NSLog(@"修改Copy数组%p    %@",copyArr,copyArr);

//    NSLog(@"修改MutableCopy数组%p    %@",mutableArr,mutableArr);

    /*

     2019-11-11 15:19:42.079 YJApiRequestTool[15114:277864] 原始数组0x7faba8507530    (

     (

     1,

     2

     )

     )

     2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] Copy数组0x7faba8507530    (

     (

     1,

     2

     )

     )

     2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] MutableCopy数组0x7faba850ad00    (

     (

     1,

     2

     )

     )

     2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] 修改数组0x7faba8507530    (

     (

     1,

     2,

     3

     )

     )

     2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] 修改Copy数组0x7faba8507530    (

     (

     1,

     2,

     3

     )

     )

     2019-11-11 15:19:42.080 YJApiRequestTool[15114:277864] 修改MutableCopy数组0x7faba850ad00    (

     (

     1,

     2,

     3

     ),

     4

     )


     copy 指针拷贝 指向的是同一块内存地址

     MutableCopy 是对象拷贝一份 修改值后 不影响之前的值

     这里或许有个疑问 originArr 为什么会是[(1,2,3)];这个其实很容易理解的 那是因为 指针指向的这块内存区域值发生了改变 所以才是[(1,2,3)]

     因此: 数组复制,其元素对象始终是指针复制,元素指向的值改变,数组自然都会改变。

     */


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

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

//        NSArray *copyArr = [originArr copy];

//        NSMutableArray *mutableArr = [originArr mutableCopy];

//

//        NSLog(@"原始数组%p    %@",originArr,originArr);

//        NSLog(@"Copy数组%p    %@",copyArr,copyArr);

//        NSLog(@"MutableCopy数组%p    %@",mutableArr,mutableArr);

//

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

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

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

//

//        NSLog(@"修改数组%p    %@",originArr,originArr);

//        NSLog(@"修改Copy数组%p    %@",copyArr,copyArr);

//        NSLog(@"修改MutableCopy数组%p    %@",mutableArr,mutableArr);

    /*

     2019-11-11 15:26:05.199 YJApiRequestTool[15278:283199] 原始数组0x7fbcdd61b7c0    (

     1,

     2

     )

     2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] Copy数组0x7fbcdd61e090    (

     1,

     2

     )

     2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] MutableCopy数组0x7fbcdd61d480    (

     1,

     2

     )

     2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] 修改数组0x7fbcdd61b7c0    (

     1,

     2,

     5

     )

     2019-11-11 15:26:05.200 YJApiRequestTool[15278:283199] 修改Copy数组0x7fbcdd61e090    (

     1,

     2

     )

     2019-11-11 15:26:05.201 YJApiRequestTool[15278:283199] 修改MutableCopy数组0x7fbcdd61d480    (

     1,

     2,

     4

     )


     对于可变数组,可以看到不管哪种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];//创建一个Person对象

person1.age=20;

person1.name=@"张三";

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

运行程序,将会发生崩溃,并输出以下错误信息:

[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.让类实现NSCopying/NSMutableCopying协议。

2.让类实现copyWithZone:/mutableCopyWithZone:方法

所以让我们的Person类能够复制自身,我们需要让Person实现NSCopying协议;然后实现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

运行之后发现我们实现了对象的复制:

同时需要注意的是如果对象中有其他指针类型的实例变量,且只是简单的赋值操作:person.obj2 = self.obj2,其中obj2是另一个自定义类,如果我们修改obj2中的属性,我们会发现复制后的person对象中obj2对象中的属性值也变了,因为对于这个对象并没有进行copy操作,这样的复制操作不是完全的复制,如果要实现完全的复制,需要将obj2对应的类也要实现copy,然后这样赋值:person.obj2 = [self.obj2 copy]。如果对象很多或者层级很多,实现起来还是很麻烦的。如果需要实现完全复制同样还有另有一种方法,那就是归档:

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

这样我们就实现了自定义对象的复制,需要指出的是如果重写copyWithZone:方法时,其父类已经实现NSCopying协议,并重写过了copyWithZone:方法,那么子类重写copyWithZone:方法应先调用父类的copy方法复制从父类继承得到的成员变量,然后对子类中定义的成员变量进行赋值:

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

idobj=[supercopyWithZone:zone];

//对子类定义的成员变量赋值

...

returnobj;

}

关于mutableCopy的实现与copy的实现类似,只是实现的是NSMutableCopying协议与mutableCopyWithZone:方法。对于自定义的对象,在我看来并没有什么可变不可变的概念,因此实现mutableCopy其实是没有什么意义的,在此就不详细介绍了。

3、定义属性的copy指示符

如下段代码,我们在定义属性的时候使用了copy指示符:

#import

@interfacePerson:NSObject

@property(nonatomic,copy)NSMutableString *name;

@end

使用如下代码来进行测试:

Person *person1=[[Personalloc]init];//创建一个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方法),程序实际上会使用参数的副本对name实际变量复制。也就是说,setName:方法的代码如下:

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

_name=[namecopy];

}

copy方法默认是复制该对象的不可变副本,虽然程序传入的NSMutableString,但程序调用该参数的copy方法得到的是不可变副本。因此,程序赋给Person对象的name实例变量的值依然是不可变字符串。

注意:定义合成getter、setter方法时并没有提供mutableCopy指示符。因此即使定义实例变量时使用了可变类型,但只要使用copy指示符,实例变量实际得到的值总是不可变对象。

copy与mutableCopy还有一个特点:

修改源对象的属性和行为,不会影响副本对象

修改副本对象的属性和行为,不会影响源对象

互不影响

4.block-copy

对于block为什么用copy 你应该就理解了 这里有一个知识点 block默认保存在栈区

     栈区在对外部对象进行操作时,不会对对象进行retain,当block保存在堆区时,在外部对象进行操作时,会对对象进行retain。而我们本是是不知道什么时候什么时候调用block的,当block中的对象提前释放,会造成Crash,但这时又回出现循环引用又该怎么办

     __weak typeof(self)weakself = self; 即可解决

     使用__block 来修饰 这会把 栈中的内存地址放到了堆中 如果不使用__block

     他会出现俩个指针地址

/*

 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();

*/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容