美文网首页
copy和mutable-copy

copy和mutable-copy

作者: 冷武橘 | 来源:发表于2020-04-19 21:24 被阅读0次

    首先我们测试一下这两行代码:

    • 测试一:源对象为可变字符串
    - (void)test1{
         NSMutableString *string=[NSMutableString stringWithFormat:@"1234"];//源对象:不可变字符串
         NSString *str1=[string copy];//深拷贝
        //只要调用了copy返回对象就是不可变字符串,而源对象是可变字符串,为了不影响源对象字符串,将会内容拷贝一份生成新的对象字符串。
        NSLog(@"%p %p",string,str1);//地址不一样,说明产生了新对象
        NSLog(@"%@ %@",string,str1);//内容一样,说明拷贝了内容
        
        NSMutableString *str2=[string mutableCopy];//深拷贝
        //只要调用了mutableCopy返回对象就是可变字符串,而源对象是也是可变字符串,为了不影响源对象字符串,将会内容拷贝一份生成新的对象字符串。
        NSLog(@"%p %p",string,str2);//地址不一样,说明产生了新对象
        NSLog(@"%@ %@",string,str2);//内容一样,说明拷贝了内容
    }
    
    • 测试二:源对象为不可变字符串
    - (void)test2{
     NSString *string=@"1234";//源对象:不可变字符串
        NSString *str1=[string copy];//浅拷贝
        //只要调用了copy返回对象就是不可变字符串,而源对象是不可变字符串,返回对象也是不可变的字符串,因此系统索性会直接拷贝一份内存地址,不会产生新的对象字符串。
        NSLog(@"%p %p",string,str1);//打印地址一样,说明了没有新对象产生
        NSLog(@"%@ %@",string,str1);//打印一样说明了,说明拷贝了地址
        
        
        NSMutableString *str2=[string mutableCopy];//深拷贝
        //只要调用了mutableCopy返回对象就是可变字符串,而源对象是是不可变字符串,为了不影响源对象字符串,将会内容拷贝一份生成新的对象字符串。
        NSLog(@"%p %p",string,str2);//地址不一样,说明产生了新对象
        NSLog(@"%@ %@",string,str2);//内容一样,说明拷贝了内容
    
    }
    

    总结:字符串的拷贝,只要拷贝后是可变的还是不可变的只取决于是调用了copy还是mutablecopy,只要调用了copy返回对象就是不可变字符串,只要调用了mutableCopy返回对象就是可变字符串.源对象为不可变字符串时,并调用了copy方法时属于浅拷贝。浅拷贝就是指针的拷贝不会产生新对象,深拷贝是内容的拷贝会产生新对象。结合上面的例子和经验,继续测试一下

    • 测试三:源对象为数组
    - (void)test3{
       NSMutableArray *Marray=[NSMutableArray arrayWithObjects:@"1", nil];
        NSArray *array=[Marray copy];//只要调用了copy返回对象就是不可变的
        NSLog(@"%p %p",Marray,array);
        NSLog(@"%@ %@",Marray,array);
       //地址不一样,内容一样:深拷贝;
        
        NSMutableArray *mutablearray=[Marray mutableCopy];//只要调用了mutablecopy返回对象就是可变的
        NSLog(@"%p %p",Marray,mutablearray);
        NSLog(@"%@ %@",Marray,mutablearray);
        //地址不一样,内容一样:深拷贝;
        
        
        NSArray *array1=@[@"2",@"2"];
        NSArray *array11=[array1 copy];//浅拷贝
        NSLog(@"%p %p",array1,array11);
        NSLog(@"%@ %@",array1,array11);
       //地址一样,内容一样:浅拷贝;
        
        NSMutableArray *array2=[array1 mutableCopy];
        NSLog(@"%p %p",array1,array2);
        NSLog(@"%@ %@",array1,array2);
       //地址不一样,内容一样:深拷贝;
    
    }
    

    总结:字符串,数组,字典.....的拷贝过程一样,只要调用了mutablecopy返回对象就是可变的,只要调用了copy返回对象就是不可变的。只要源对象是不可变的,调用了copy,只是指针的拷贝,不会有新对象的产生是浅拷贝, 而调用了mutablecopy,就会产生新对象,是深拷贝。其他的源对象是可变的,都属于深拷贝。

    自定义类的拷贝

    - (void)viewDidLoad {
        [super viewDidLoad];
        Person *p=[[Person alloc]init];
        p.name=@"张三";
        p.age=@"24";
        Person *p1=[p copy];
        NSLog(@"%@ %@",p1.age,p1.name);
    }
    
    #import "Person.h"
    @interface Person()<NSCopying>
    
    @end
    @implementation Person
    - (id)copyWithZone:(NSZone *)zone{
        Person *p=[[Person allocWithZone:zone]init];
        p.age=self.age;
        p.name=self.name;
        
        
        return p;
    }
    
    @end
    

    属性copy,strong

    • copy修饰属性
    #import "ViewController.h"
    @interface ViewController ()
    @property(nonatomic,copy)NSArray *array;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
     NSMutableArray *MArray=[NSMutableArray array];
        self.array=MArray;
        NSLog(@"%p %p",MArray,self.array);//打印得到内存地址不同
        [MArray addObject:@"1"];
        //Marray数组添加元素@“1”后,Marray不发生变化
        NSLog(@"%@ %@",MArray,self.array);//打印得到内容不同,说明Marray与self.array互不影响
        
    }
    - (void)setArray:(NSArray *)array{
        NSArray *arr=[array copy];//深拷贝,arr与array是不同的对象
       _array=arr;//_array与array是不同的对象
    }
    

    代码说明:以copy修饰的属性,调用的set方法如上:在给成员变量赋值之前,内部先要调用copy方法返回不可变对象,由于源对象Marray是可变的,所有会深拷贝,重新生一个数组对象。即:self.array=Marray是两个不同内存的对象,以后两者改变互不影响。

    • copy修饰可变对象所引起的崩溃错误
    #import "ViewController.h"
    @interface ViewController ()
    @property(nonatomic,copy)NSMutableArray *array;
    @end
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.array=[NSMutableArray arrayWithObjects:@"1", nil];
        [self.array addObject:@"1"];
    }
    

    运行以上代码后会崩溃: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI addObject:]: unrecognized selector sent to instance 0x6100000043c0'这就是因为错误的修饰所造成的错误。上面代码属性array用copy修饰后返回的真实对象类型是不可变的,即self.array是不可变数组,而不可变数组是不能进行数组的修改,因此系统会以找不到方法2⃣️发生崩溃

    • strong修饰属性
    #import "ViewController.h"
    @interface ViewController ()
    @property(nonatomic,strong)NSArray *array;
    @end
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSMutableArray *MArray=[NSMutableArray array];
        self.array=MArray;
        NSLog(@"%p %p",MArray,self.array);//打印得到内存地址相同
        [MArray addObject:@"1"];
        //Marray数组添加元素@“1”后,self.array也会添加元素@“1”,因为self.array与Marray所指向的同一地址的对象。
        NSLog(@"%@ %@",MArray,self.array);//内容相同,Marray与self.array互相影响。
    }
    - (void)setArray:(NSArray *)array{
       _array=array;//_array与array指针拷贝
    }
    

    代码说明:以strong修饰的属性,set方法赋值就是单纯的指针拷贝,不会有新对象产生。即self.array=Marray是两个相同内存的同一个对象,两者改变互相影响。
    总结:以stong或copy修饰的属性的区别是:copy在赋值前会先调用copy返回一个不可变对象再赋值给成员变量,set方法传入的源对象如果是可变的,返回的不可变对象就是深拷贝出的一个新对象,这样成员变量和源对象就是两个不同对象,因此两者也不会相互影响。而以strong修饰的属性就是单纯的浅拷贝,最终也是同一对象,两者会互相影响。数组,字典,字符串道理同上。。。。。。。。。。

    相关文章

      网友评论

          本文标题:copy和mutable-copy

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