iOS中的修饰关键字
1. iOS中定义属性、变量的修饰关键字
在声明@property 属性、变量时,总是要在括号中写上assign、retain、copy、weak、strong其中的几个,他们具体有什么区别呢?我们先说说assign、retain、copy这三个:
assign
assign一般用来修饰基础数据类型 (NSInteger、CGFloat、int、float、double、char等)。因为assign声明的属性不会增加引用计数,属性释放后就没有了。若assign修饰的指针指向的是一个对象类型,被指向的对象dealloc后,对象的这个指针却还在,被调用时只会crash)。所以一般只用来声明基本的数据类型,因为它们会被分配到栈上,而栈会由系统自动处理,不会造成野指针。
retain
与assign相对,retain声明后的对象会更改引用计数(被引用,引用计数+1,释放后会-1。即使这个对象本身释放了,只要还有对象在引用它,就会被持有)。只有当引用计数为0时,就被dealloc析构函数回收。
copy
最常见使用copy来修饰的是NSString。copy与retain的区别在于retain的引用是拷贝指针地址,而copy是拷贝对象本身,也就是说retain是浅复制,copy是深复制。如果是浅复制,当修改对象值时,都会被修改,而深复制不会。之所以在NSString这类有可变类型的对象上使用,是因为它们有可能和对应的可变类型如NSMutableString之间进行赋值操作,为了防止内容被改变,使用copy去深复制一份。copy工作由copy方法执行,此属性只对那些实现了NSCopying协议的对象类型有效。
以上三个可以在MRC中使用,但是weak和strong就只能在ARC中使用,也就是自动引用计数,这时就不能手动去进行retain、release等操作了,ARC会帮我们完成这些工作。
weak:
weak类似于assign,叫弱引用,不增加引用计数。在防止循环引用时使用(比如父类引用了子类,子类又去引用父类)。IBOutlet、Delegate一般用的就是weak,这是因为它们会在类外部被调用,防止循环引用。
strong:
相对的,strong就类似于retain了,叫强引用,会增加引用计数,类内部使用的属性一般都是strong修饰的,现在ARC已经基本替代了MRC,所以我们最常见的就是strong了。
nonatomic:
在定义属性时,括号内往往还会加一个nonatomic,它的名字叫非原子访问。对应的有atomic,是原子性的访问。如果一个属性是由atomic修饰的,那么系统就会进行线程保护,防止多个写操作同时进行。这有好处,但也有坏处,那就是消耗系统资源。所以对于iPhone这种移动设备,如果不是进行多线程的写操作,就可以使用nonatomic,取消线程保护以提高性能。
2. block外部weak 内部strong 防止循环引用
大家都看到别人在block里面使用self或者self的属性的时候要使用__weak修饰self,然后才能block里面使用,在block里面使用的时候又将weakSelf使用__strong修饰进行使用,比如:
__weak __typeof(self) weakSelf <wbr> = self;
self.block = ^{
__strong __typeof(self) strongSelf = weakSelf;
[strongSelf doSomeThing];
[strongSelf doOtherThing];
};
- 为什么使用weakSelf
通过 clang -rewrite-objc 源代码文件名 将代码转为c++代码(实质是c代码),可以看到block是一个结构体,它会将全局变量保存为一个属性(是__strong的),而self强引用了block这会造成循环 引用。所以需要使用__weak修饰的weakSelf。
- 为什么在block里面需要使用strongSelf
是为了保证block执行完毕之前self不会被释放,执行完毕的时候再释放。这时候会发现为什么在block外边使用了__weak修饰self,里面使用__strong修饰weakSelf的时候不会发生循环引用?! 另外,strongSelf只是为了保证在block内部执行的时候不会释放,但存在执行前self就已经被释放的情况,导致strongSelf=nil。注意判空处理。
- 不会引起循环引用的原因
因为block截获self之后self属于block结构体中的一个由__strong修饰的属性会强引用self, 所以需要使用__weak修饰的weakSelf防止循环引用。block使用的__strong修饰的weakSelf是为了在block(可以理解为函数)生命周期中self不会提前释放。strongSelf实质是一个局部变量(在block这个“函数”里面的局部变量),当block执行完毕就会释放自动变量strongSelf,不会对self进行一直进行强引用。
3. weak的实现原理
参考文章:
http://www.cocoachina.com/articles/11990
http://www.cocoachina.com/articles/18962
http://shinancao.cn/2019/07/15/iOS-weak/
https://luowei.github.io/原理/16070583973992.html