ARC 简介
从 iOS 5开始,OC 引进了一种 ARC(Automatic Reference Counting)的方式来管理内存,由编译器来为我们生成相应的内存管理代码。
在类属性的声明中,ARC 相关的修饰词有 4 个:
strong
一个对象只要存在一个 strong 类型的指针指向它,就不会被释放。weak
不会延长对象的生命周期,当weak
类型的指针指向的对象被释放时,指针自身会被自动置为nil
。assign
用于 C 原始类型,比如 int。copy
传入对象时会浅拷贝对象。一般将不可变的 property 设置为 copy,当可变的对象传入时,编译器会自动拷贝一份不可变的版本,以保证其内容不会被修改。如果传入的不可变对象,会增加其引用计数。
当 property 是一个 block 时通常使用 copy。因为 block 需要在其所在的 scope 之外保留其捕获的状态。不声明也是可以的,但官方推荐这样使用,以提醒代码阅读者。
在 ARC 机制下,指针缺省的类型是 strong
。
在声明局部变量时,有四个 ARC 相关的修饰词,他们的用法跟 const 类似。
__strong
缺省值。用法同strong
。__weak
用法同weak
。__unsafe_unretained
类似于weak
,但其指向的对象被释放时,其值不会被置为nil
。应该是由于兼容性的原因而存在,通常不建议使用。__autoreleasing
用来修饰一个以引用(id *)方式传入的参数,当函数返回值时被释放。
上面的修饰词正确的使用方法是
ClassName * qualifier variableName;
修饰词放在其他位置也可以编译通过,但是严格来说是不正确的。
循环引用以及避免方法
当两个对象使用 strong
指针互相引用时,就会出现双方都不会被释放的情况,经常出现在使用 block 的地方。
例如下面的代码就存在循环引用:
@property (strong) void(^someBlock)();
[self setSomeBlock:^{
[self doSomething];
}];
在属性的生命中,类的对象含有一个 strong 类型的指针指向 block,在 block 中又存在 self (默认是 strong 类型)来引用类的对象,这样两者在生命周期结束时都不会被释放。
解决方法:通过使用__weak
修饰词来得到一个指向 self 的 weak 指针来打破循环引用。
@property (strong) void(^someBlock)();
MyClass *__weak weakSelf = self;
[self setSomeBlock:^{
MyClass *__strong strongSelf = weakSelf;
[strongSelf doSomething];
}];
block 内部的 strong 指针是为了保证在 block 执行的过程中,对象不会被释放掉。其实也可以先判断一下 weakSelf 是否为空。
但不应在所有使用 block 的情况下都采用 weakSelf,因为只要类中不存在指向 block 的 strong 指针,就不会存在循环引用。而滥用weakSelf 可能会导致某些情况下 self 被释放后才调用 block,此时 block 中的代码不会被执行,往往不是我们期望的。