类的Copy
一个对象要想实现自己的copy,该类或者改结构体要实现NSCopying或NSMutableCopying协议。
我们先看类实现NSCoping和NSMutableCopying是怎样的结果
NSCopying
class People: NSObject, NSCopying {
var name: String = ""
init(name: String) {
self.name = name
}
func copy(with zone: NSZone? = nil) -> Any {
return self //返回自身的引用
}
}
- 创建一个实例对象
let p = People(name: "Bill")
- copy出一个对象,我们发现这两个对象指向的地址是同一块。
let copyP = p.copy() as! People
print("p的地址:\(p)")
print("copyP的地址:\(copyP)")
- 我们修改copy出对象的name,我们发现p的name也跟着发生变化了。大家返回去看一下我们的People的NSCopying协议的实现return self ,它并没有在内存里进行重新复制一份新的,而是把自己引用返回了。
copyP.name = "Jason"
- 有人就说了,我该如何实现一个完全新的对象哪,它的修改不会影响到另外一个对象。这就要我们在内存里重新生成一个新的实例。请看以下代码和上面的哪里不一样吗?
class People: NSObject, NSCopying {
var name: String = ""
required init(name: String) {
self.name = name
}
func copy(with zone: NSZone? = nil) -> Any {
return type(of: self).init(name: self.name)
}
}
- 把刚才的打印重新来一遍看看
let p = People(name: "Bill")
let copyP = p.copy() as! People
print("p的地址:\(p)")
print("copyP的地址:\(copyP)")
copyP.name = "Jason"
print("p的name:\(p.name)")
print("copyP的name:\(copyP.name)")
- 我们在copy里重新使用init函数重新生成了一个新的实例。
NSMutableCopying
-将我们的协议换成NSMutableCopying实现mutableCopy函数。将我们以上的步骤在重新走一遍,观察一下有没有变化。
注意这里不一样了
let copyP = p.mutableCopy() as! People
- 到这里我们发现NSMutableCopying 和 NSCopying之间并没有什么区别,那为什么苹果要整两个协议类。思考中。。。。。Mutable可变的意思,我们知道OC中有NSMutableArray和NSArray好多带有NSMUtable的类,这些类就是可变的。比如下面的列子。
NSArray *datas = @[@(1), @(2), @(3)];
NSArray *copyDatasArray = datas.copy;
- 我们发现两者的地址一样,根据我们上面的知识我们可以推断 NSArray 对 NSCopying 协议的实现只是简单地返回了其本身。可能就像下面代码一样:
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- 那我们在看一下NSArray是否实现了NSMutableCopying协议。
NSArray *datas = @[@(1), @(2), @(3)];
NSArray *copyDatasArray = datas.mutableCopy;
我们发现这次两者地址不同了,那你猜到了苹果是如何实现NSMutableCoping协议了吗?那我们在看看NSMutableArray
copy
NSMutableArray *datas = [NSMutableArray arrayWithObjects:@(1), @(2), @(3), nil];
NSMutableArray *copyDatasArray = datas.copy;
- mutableCopy
NSMutableArray *datas = [NSMutableArray arrayWithObjects:@(1), @(2), @(3), nil];
NSMutableArray *copyDatasArray = datas.mutableCopy;
- 通过以上测试我们可以得出一下结论,对于不可变的数组,实现copy时只是返回本身引用。不管是可变数组或者非可变数组只要调用了mutablecopy都会重新复制一份新的。
为什么mutalecopy会复制一份新的哪
本质上,一个不可变对象是不需要拷贝的。因为,无论你持有了不可变对象本身,还是持有了不可变对象的拷贝,如果有了不变的保证,在任何情况下,使用两个对象中的任何一个都是没有区别的。
- 不可变的好处
不用担心副作用,内存开销,线程安全
- 那还要可变的有啥用处。
OC本质上还是一个面向对象的命令式的编程语言。以可变的对象表达状态的变化是这一编程范式的基础建模方式之一。
结论
所以apple会认为当我们copy一个对象时如果该对象是不可变的那么就没有必要重新给它复制一个新的如果copy是一个可变的,那么苹果认为你要copy出一个新的,但是又不能影响原先可变的对象。
当我们mutablecopy一个对象时,苹果都会给我们创建一个新的可修改的对象。
一句话总结
copy返回一个不可变对象,mutablecopy返回一个可变对象。
Swift中的数组和字典
Swift 中数组(Array)和字典(Dictionary)类型均以结构体的形式实现。然而当数组被赋予一个常量或变量,或被传递给一个函数或方法时,其拷贝行为与字典和其它结构体有些许不同。在Swift 的后台中,只有确有必要,实际(actual)拷贝才会被执行。Swift 管理所有的值拷贝以确保性能最优化的性能,所以你也没有必要去避免赋值以保证最优性能。(实际赋值由系统管理优化)
喜欢楼主的关注一下毕竟第一次写博客。欢迎加我微信一起探讨技术。
我们会在下一篇文章中去讨论结构体和类,这里swift数组和字典会在下一节讲。