目录
- 1. 引用计数
- 2 ARC4种所有权修饰符: __weak,__strong,__autoreleasing,__unsafe_unretained
- 2. Retain Cycle 问题及解决
- 3 总结
1. 引用计数
在ARC时代,为什么我们还要理解MRC下的引用计数?原因主要有二:
-
ARC并非万能。理解引用计数是我们解决循环引用的基础;
-
了解引用计数可以加深对OC内存管理的理解。
1.1 MRC vs ARC
新开1个工程,在Build Phases的AppDelegate.m里添加-fno-objc-arc,可以开启MRC模式。
_ARC/MRC command.png)
输入如下代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// AppDelegate.m
#define isARC 1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
#if isARC == 0 //-fno-objc-arc
NSObject *object = [[NSObject alloc] init];
NSLog(@"Reference Count = %u", [object retainCount]); //1
NSObject *anotherObject = [object retain];
NSLog(@"Reference Count = %u", [anotherObject retainCount]); //2
[anotherObject release];
NSLog(@"Reference Count = %u", [anotherObject retainCount]); //1
[object release];
NSLog(@"Reference Count = %u", [anotherObject retainCount]); //1, why not 0?
#elif isARC == 1
NSObject *object = [[NSObject alloc] init];
NSLog(@"Reference count = %ld", CFGetRetainCount((__bridge CFTypeRef)object)); //1
//[object retain];
NSObject *anotherObject = object;
NSLog(@"Reference count = %ld", CFGetRetainCount((__bridge CFTypeRef)object)); //2
anotherObject = nil;
//[object release];
NSLog(@"Reference count = %ld", CFGetRetainCount((__bridge CFTypeRef)object)); //1
object = nil;
//[object release];
NSLog(@"Reference count = %ld", CFGetRetainCount((__bridge CFTypeRef)object)); //Thread 1: EXC_BREAKPOINT(code=EXC_I386_BPT,subcode=0X0)
#endif
return YES;
}
在MRC模式下(-fno-objc-arc),我们可以看到:
1.在实例化NSObject时,object指向了该实例,因此该实例retainCount从0变为1。
2.anotherObject也指向该实例,并且retain,则retainCount从1变为2。如果是用=object而不是=[object retain]则retainCount依旧是1。
3.anotherObject release使得该实例retainCount-1。
4.object release使得该实例retainCount-1变为0释放。但是为什么retainCount输出还是1呢?因为该对象的内存已经被回收,而我们向一个已经被回收的无效对象发了一个retainCount消息,所以它的输出结果应该是不确定的。不将无效对象的这个值从1变成0,可以减少一次内存的写操作,加速对象的回收。
在ARC模式下(删除-fno-objc-arc),retain和release是由系统自动加入到适当的位置的:
-
实例化过程引用计数和MRC一样。若增加
__weak修饰符,则NSObject实例之初就会被释放。 -
这和3一样。
-
object = nil会使实例retainCount减1。这里减1后为0。 -
向已释放的实例发送
CFGetRetainCount((__bridge CFTypeRef)object)(ARC下retainCount已被禁止)会触发野指针错误。
2 ARC4种所有权修饰符: __weak,__strong,__autoreleasing,__unsafe_unretained
属性修饰符对应的4种所有权修饰符如下所示:
_ARC/ARC4种对象所有权修饰符 vs 属性修饰符.png)
2.1 __weak
表示弱引用,对应属性修饰符weak。弱应用对对象的生命周期无影响。对象在被释放的同时,指向它的弱引用会被自动置为nil,这个技术称为zeoring weak pointer。这样有效地防止了野指针的产生。__weak用在防止循环引用的场景中(如delegate,block)和无效的强引用中(如@IBOutlet)。
2.2 __strong
表示强引用,对应属性修饰符strong和copy。当所有对象没有任何一个强引用时,才会被释放。如果在声明时不加修饰符,默认是强应用。当需要释放强引用指向的对象时,需要将强引用置nil。
2.3 __autoreleasing
2.4 __unsafe_unretained
和__weak一样,但对象释放后,不会自空,所以非常不安全。由于ARC是在iOS 5引入的,而这个修饰符主要是兼容iOS 4以及更低版本的设备,现在可以完全忽略这个修饰符了,因为iOS 4早已退出历史舞台很多年。
2. Retain Cycle 问题及解决
。
2.1 Retain Cycle 问题
3 总结
。