关于NSCopying协议,深拷贝,浅拷贝

1.想让一个类实现copy方法就要遵循NSCopying协议

如果想让类实现copy方法,就要遵循NSCopying协议,同时重写这个协议的唯一一个方法copyWithZone方法。

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

⚠️:其实我们并不是重写了copy方法,而是重写了copyWithZone方法

2.如果想让一个类有可变版本和不可变版本就要同时遵循NSCopying协议和NSMutableCopying协议

NSMutableCopying协议里只有一个方法:

-(id)mutableCopyWithZone:(NSZone*)zone;

3.可变版本和不可变版本

无论当前实例是否可变,若需获取其可变版本的拷贝都应该调用mutableCopy方法,如果要获得不可变版本的拷贝就应该调用copy方法。

[NSMutableArray copy]=>NSArray

[NSArray mutableCopy]=>NSMutableArray

但是这么做是不安全的,比如说一个类本来是可变的,然后copy之后变成了不可变的,这个时候再去调用以前的可变类的方法会crash。

4.深拷贝和浅拷贝

⚠️:这里有一个特别重要的误区,不是说调用copy方法就是浅拷贝,调用mutablecopy就是深拷贝,并没有专门定义深拷贝的协议,所以深拷贝方法的实现是需要自己去确定的。

浅拷贝:浅拷贝是对指针的拷贝,对一个对象进行浅拷贝,相当于拷贝了一个指向它的指针,相当于把对象的引用计数加1,指针指向的内存地址就是原对象的内存地址。

深拷贝:深拷贝是对值的拷贝,相当于拷贝出了一个完全新的对象,只是对象的值和原对象的值相等。

非容器对象:

    NSString* string = @"laowang";

    NSString* str1 = [string copy];

    NSString* str2 = [string mutableCopy];

    NSLog(@"string:%p",string);

    NSLog(@"str1:%p",str1);//和string是一个内存地址

    NSLog(@"str2:%p",str2);//和string是不同的内存地址

⚠️打印结果:

string:0x10265c060、str1:0x10265c060、str2:0x7f8b7ae96860

对于不可变的非容器对象,copy是浅拷贝,mutableCopy是深拷贝

对于可变的非容器对象,无论是copy还是mutableCopy都是深拷贝,拷贝出来的都是新的对象。

    NSMutableString* mtr = [NSMutableString stringWithFormat:@"laowang"];

    NSString* mtr1 = [mtr copy];

    NSString* mtr2 = [mtr mutableCopy];

    NSMutableString* mtr3 = [mtr copy];这里这个mtr3虽然写的是可变字符串,但是调用可变字符串的方法appendString程序会崩溃!

    NSMutableString* mtr4 = [mtr mutableCopy];

    NSLog(@"mtr=%p",mtr);

    NSLog(@"mtr1=%p",mtr1);

    NSLog(@"mtr2=%p",mtr2);

    NSLog(@"mtr3=%p",mtr3);

    NSLog(@"mtr4=%p",mtr4);

结果:mtr=0x7faaf8d1e7c0、mtr1=0xa676e61776f616c7、mtr2=0x7faaf8d1e800

mtr3=0xa676e61776f616c7、mtr4=0x7faaf8d1e840

不可变容器对象:

    NSArray* array = [NSArray arrayWithObjects:@"1",@"2",@"3", nil];

    NSArray* array1 = [array copy];//浅拷贝

    NSArray* array2 = [array mutableCopy];//深拷贝

    NSLog(@"array = %p",array);

    NSLog(@"array1 = %p",array1);

    NSLog(@"array2 = %p",array2);

结论:array = 0x7f8073426bd0、array1 = 0x7f8073426bd0、array2 = 0x7f8073426c00

:copy对容器对象本身是浅拷贝,对容器对象内对象也是浅拷贝

mutableCopy 对容器对象本身是深拷贝,对容器对象内对象也是浅拷贝

可以用一个图说明:

浅拷贝
深拷贝

可变容器对象的拷贝:

无论是copy还是mutableCopy对容器对象本身都是深拷贝,但是对于容器对象内的每个对象都是浅拷贝(指针拷贝)

所以说foundation框架里的这些集合类都没有实现真正意义上的深拷贝,就是既对集合本身深拷贝,也对集合内的每个对象深拷贝,要想实现这样的深拷贝需要我们自己去给类添加深拷贝的实现方法。

实现完全深拷贝:

- (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag;

NSMutableArray *marry1 = [[NSMutableArray alloc] init];

NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];

NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];

[marry1 addObject:mstr1];

[marry1 addObject:mstr2];

NSArray *marray2 = [[NSArray alloc] initWithArray:marry1 copyItems:YES];

marray2里的每一个元素的内存地址和marry1里的都不同,所以说容器内的每个元素也是深拷贝。

你可能感兴趣的:(关于NSCopying协议,深拷贝,浅拷贝)