美文网首页iOS开发知识小集
iOS开发中为什么要使自定义类具有拷贝(copy、mutable

iOS开发中为什么要使自定义类具有拷贝(copy、mutable

作者: 梁森的简书 | 来源:发表于2019-04-09 17:28 被阅读158次

系统自带类如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都是深拷贝(主要还是看两个代理方法的实现 )。

****本篇文章到这里就结束了,愿大家加班不多工资多,男同胞都有女朋友,女同胞都有男朋友。😊***

相关文章

网友评论

    本文标题:iOS开发中为什么要使自定义类具有拷贝(copy、mutable

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