美文网首页
Copy与MutabCopy

Copy与MutabCopy

作者: BLUEVIPIOS_ | 来源:发表于2017-09-25 11:14 被阅读0次

    先说结果下面会一一测试

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

    */

    相关文章

      网友评论

          本文标题:Copy与MutabCopy

          本文链接:https://www.haomeiwen.com/subject/pwmfextx.html