Copy与MutabCopy

2017-09-25  本文已影响0人  BLUEVIPIOS_

先说结果下面会一一测试

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

*/

上一篇下一篇

猜你喜欢

热点阅读