最近老有朋友问我一些关于OC中声明属性中关键字的细节使用,第一为了梳理下自己的思路为了日后好查找,第二为了省事就写一篇这个总结文章吧。
声明一个属性的过程中,一共分三类关键字:读写权限关键字,原子性关键字以及引用计数关键字
1.读写权限关键字:readonly,readwirte,默认是readwirte,顾名思义就不过多解释了
2.原子性关键字:atomic,nonatomic,默认是atomic原子性。这里区分一下atomic与nonatomic的区别,atomic保证了原子内部的线程安全,其实本质上也就是给属性的setter方法中加了一个线程锁,要知道OC内部实现时是用MRC实现的,所以自然在setter方法中也有retain与release方法的调用,使用atomic关键字的好处就是当多条线程访问同一个属性的时候,只有一条线程能够进行操作,这样就避免了在多条线程操作属性时,一条线程执行到了release方法另一条线程又拿到相关对象造成的空指针报错问题(这只是其中一个好处),但坏处就是会耗性能,而且大多数情况下用不到,而且在一些比较复杂的情况下的时候,atomic也并不能提现出比nonatomic更多的优势,所以一般使用的是性能更高的nonatomic关键字
3.引用计数关键字:1.retain/strong 2.assgin/unsafe_unretained 3.weak 4.copy
对于这四个引用计数的关键字retain和unsafe_unretained都是MRC中用的,就不过多解释了
1.先从strong开始写起,strong就代表给对象赋值的时候赋予对象的是一个指针,会使给对象赋值的那个对象引用计数+1,不会开辟新的内存空间,一般用于实例变量。
2.assgin一般是一个修饰基本数据类型的关键字,当然也可以修饰对象,使用assgin关键字不会增加其引用计数,但是当指向的对象被释放的时候,会产生一个悬浮指针,仍然指向空地址,这样就会造成内存泄漏或者野指针之类常见的不必要的麻烦
3.weak和assgin关键字很相似,但是weak只能是一个修饰对象的关键字,不能修饰基本数据类型,使用weak不会使对象的引用计数+1,但weak修饰的对象在被释放的时候不会产生一个悬垂指针,只会将对象置为nil
其实这里就解释了为什么一般破循环引用的环是用weak而不是用assgin了,也做了assgin和weak的区别了
4.copy关键字指的是拷贝,但是具体是深拷贝还是浅拷贝要联系上下文决定,稍后我详细写。一般情况下是将一个对象内存中的内容拷贝一份,重新开辟一块新的空间进行赋值,再将引用copy关键字的属性指向这块区域。使用copy关键字会新开辟一块内存区域,但不会使赋值的对象引用计数+1。
所以引用计数的4个关键字就解释完了,下面来区分一下拷贝中使用的mutableCopy和copy的区别:
首先,需要使用这两个方法必须在类中遵守NSCopying或者NSMutableCopying协议,不然会报错。
然后对于不同的情况,拷贝的结果和拷贝的方式都有不同,详细列举一下:
首先对于可变对象来说:
使用mutableCopy产生的结果是一个可变对象,并且会使用深拷贝的拷贝方式进行拷贝,
使用copy产生的结果是一个不可变对象,并且也会使用深拷贝的方式进行拷贝。
对于不可变对象来说:
使用mutableCopy产生的结果也是一个可变的对象,并且也会采用深拷贝的方式进行拷贝,
使用copy的话产生的结果是一个不可变的对象,但是,拷贝方式就会采用浅拷贝来进行拷贝了。
这四种情况就代表了各种情况下拷贝对象的拷贝方式与拷贝结果的不同,大家可以梳理一下,其实不是很绕,
我自己总结了一下就是,使用mutableCopy拷贝出来的结果绝壁是可变的,而且是采用深拷贝的方式,但是使用copy就分情况了,他拷贝出来的东西绝壁是不可变的,但是对于可变对象来说使用的就是深拷贝的方式,对于不可变的对象就会采用浅拷贝方式拷贝指针,这样总结就比较好记了。
所以使用copy的时候切记要小心,心里要明记上面的情况,尤其开发中对于可变对象的拷贝一定要小心,不然就会产生crash等结果,比较蛋疼。
本文由作者原创,未经允许不得转载