系统自带类如NSArray、NSDictionary、NSString都具有拷贝功能,即可以直接使用copy、mutableCopy方法,对某个类的对象进行深拷贝或浅拷贝。
我们自定义的类如果也想像系统自带类那样具有拷贝功能,我们就要遵守NSCopying, NSMutableCopying协议并实现协议中的方法:
@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
@end
那么我们让自定义对象具有拷贝功能有什么用呢?
来看段代码:
self.per = [Person new];
self.per.name = @"123";
NSLog(@"指针指向的地址:%p", self.per);
Person * ls = [Person new];
ls = self.per;
NSLog(@"变化前:%@", self.per.name);
ls.name = @"234";
NSLog(@"变化后:%@", self.per.name);
NSLog(@"指针指向的地址:%p---%p", ls, self.per);
NSLog(@"指针所在的地址:%p---%p", &ls, &(_per));
Person是一个我们自定义的类。
你觉得变化后self.per.name的值是什么呢?123还是234?
想象一个场景,一个tableView,如果tableView上的Cell被点击过那么这个Cell的背景色要发生变化。你会怎么做?
我的做法:
一个tableView对应一个数据源,数据源中的每条数据对应一个Cell,对应每个Cell的数据源中有一个标识符标志着这个Cell是否被点击过。每当一个Cell被点击,那么数据源中的标识符就要发生改变。
伪代码:
for (i = 0; i < dataSource.count; i ++){
if(点击Cell的下标 == i){
Model * model = dataSource[i];
model.selected = YES;
[tableView reload];
}
}
我们拿出数据源中的某个对象(类是我们自定义的),我们队这个对象的某个属性进行修改,数据源中的这个对象的属性也发生了改变。由此我们可以得出self.per.name最终的值是234。
why?
这是因为我们将自定义对象self.per进行了一个浅拷贝,然后赋值给了对象ls,实际只是拷贝了一个新的指针,,指针_per和ls指向同一块内存区域,当我们对ls的属性name进行修改的时候即对指针ls指向的对象的属性进行修改_per指针指向的对象的属性当然也发生了改变,因为它们是同一个对象。
看下打印的结果:
2019-04-09 17:06:22.062248+0800 strong修饰属性[8183:1124770] 指针指向的地址:0x60c00000eec0
2019-04-09 17:06:22.062481+0800 strong修饰属性[8183:1124770] 变化前:123
2019-04-09 17:06:22.062549+0800 strong修饰属性[8183:1124770] 变化后:234
2019-04-09 17:06:22.062611+0800 strong修饰属性[8183:1124770] 指针指向的地址:0x60c00000eec0---0x60c00000eec0
2019-04-09 17:06:22.062674+0800 strong修饰属性[8183:1124770] 指针所在的地址:0x7ffeecd752a8---0x7fa7a0e052a0
但是有时我们并不希望是这样,我希望被赋值后的对象是一个新对象,新对象的任何修改都不能改变原对象的值。这时就需要深拷贝,要想让自定义对象具有深拷贝功能,我们就要像文章开头说的那样做了。
协议中方法的具体实现:
#import "Person.h"
@implementation Person
- (id)copyWithZone:(NSZone *)zone{
Person * per = [[Person allocWithZone:zone] init];
per.name = self.name;
return per;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
Person * per = [[Person allocWithZone:zone] init];
per.name = self.name;
return per;
}
@end
让自定义对象使用copy方法之后:
self.per = [Person new];
self.per.name = @"123";
NSLog(@"指针指向的地址:%p", self.per);
Person * ls = [Person new];
ls = [self.per copy];
NSLog(@"变化前:%@", self.per.name);
ls.name = @"234";
NSLog(@"变化后:%@", self.per.name);
NSLog(@"指针指向的地址:%p---%p", ls, self.per);
NSLog(@"指针所在的地址:%p---%p", &ls, &(_per));
看打印结果:
2019-04-09 17:26:30.107697+0800 strong修饰属性[8227:1166464] 指针指向的地址:0x60c00001a180
2019-04-09 17:26:30.108085+0800 strong修饰属性[8227:1166464] 变化前:123
2019-04-09 17:26:30.108312+0800 strong修饰属性[8227:1166464] 变化后:123
2019-04-09 17:26:30.108462+0800 strong修饰属性[8227:1166464] 指针指向的地址:0x60c00001a270---0x60c00001a180
2019-04-09 17:26:30.108535+0800 strong修饰属性[8227:1166464] 指针所在的地址:0x7ffeed54e2a8---0x7ff202c04ea0
两个指针指向的地址是完全不同的地址。
使用mutableCopy的结果是一样的。
我们可以得出结论:在自定义对象具有拷贝功能之后(NSCopying, NSMutableCopying的协议方法按照文章中的形式进行实现),对自定义对象使用copy和mutableCopy都是深拷贝(主要还是看两个代理方法的实现 )。
****本篇文章到这里就结束了,愿大家加班不多工资多,男同胞都有女朋友,女同胞都有男朋友。😊***
网友评论