上面的文章写得已经非常全面了,不过还是有些东西需要补充一下。
循环引用
循环引用和ARC没有直接关系,但是在转换的过程中遇到了相关问题,所以就着重说明一下。
循环引用的原因
任何一种语言,都必须有它的内存管理方式。比如C语言中,我们用malloc申请一块内存,放入数据。当这块内存不在需要时,就调用free将其释放掉。这是一种比较原始的方式,当同一块内存在多个地方被用到时,到底应该由谁来释放呢?你只能小心翼翼的处理这种问题,除此之外没有别的办法。
上面的文章写得已经非常全面了,不过还是有些东西需要补充一下。
循环引用
循环引用和ARC没有直接关系,但是在转换的过程中遇到了相关问题,所以就着重说明一下。
循环引用的原因
任何一种语言,都必须有它的内存管理方式。比如C语言中,我们用malloc申请一块内存,放入数据。当这块内存不在需要时,就调用free将其释放掉。这是一种比较原始的方式,当同一块内存在多个地方被用到时,到底应该由谁来释放呢?你只能小心翼翼的处理这种问题,除此之外没有别的办法。
Objective-C相较于C的一大优势就是内存管理,提出了引用计数的概念。引用计数是针对对象的,即NSObject,不是NSObject就没必要谈引用计数。
在Objective-C中,凡是继承自NSObject的类都提供了两个方法,retain和release。当我们调用一个对象的retain时,这个对象的内存计数加1;反之,当我们调用release时, 对象的内存计数减1,只有当对象内存计数为0时,这个对象才真正会被释放,此时,对象的delloc方法会自动被调用,来做些内存回收前的工作。
那么问题就来了。比如有A和B两个对象,A持有B,B同时也持有A,按照上面的规则,A只有B释放之后才有可能释放,同样B只有A释放后才可能释放,当双方都在等待对方释放的时候, 循环引用就形成了。两个对象都永远不会被释放,这样就造成内存泄露。1
2
3
4
5
6
7
8
9
10
11
12//ARC code
@interface A : NSObject
@property (nonatomic,strong) B* b;
@end
@interface B : NSObject
@property (nonatomic,strong) A* a;
@end
解决办法也很简单,只要不让A和B同时保持对方的强引用即可。 注意,B对A的引用是weak。知道为什么我们要把Delegate对象设成weak了吧?1
2
3
4
5
6
7
8
9
10
11
12//ARC code
@interface A : NSObject
@property (nonatomic,strong) B* b;
@end
@interface B : NSObject
@property (nonatomic,weak) A* a;
@end
当Block遇到ARC
Block的概念这里就不详细解释了。我想说的是,Block就是一个对象,它能访问上下文变量,这就要保证上下文所属的对象在Block运行时必须不被释放,所以Block默认会对当前上下文进行强引用。这时如果当前对象也对Block有强引用,那么就会造成循环引用。比如下面的代码,self强引用tableView,tableView强引用block;block又强引用self,所以问题就产生了。1
2
3
4
5
6[self.tableView addPullToRefreshWithActionHandler:^{
self.isRefresh = YES;
self.hideHud = YES;
self.currentPage = 0;
[self queryCarFault];
}];
如何破局,ARC之后有一个__weak的关键字。这样Block就不会强引用BBWarningRecordTableViewController的对象了。1
2
3
4
5
6
7__weak BBWarningRecordTableViewController* weakSelf = self;
[self.tableView addPullToRefreshWithActionHandler:^{
weakSelf.isRefresh = YES;
weakSelf.hideHud = YES;
weakSelf.currentPage = 0;
[weakSelf queryCarFault];
}];
从上面的代码可以看到,我们只是加了一行代码1
__weak BBWarningRecordTableViewController* weakSelf = self;
但是有一次我发现类似的语句不止一种写法1
2
3
4
5
6
7
8
9
10// 不知道这行代码的使用场景的同学你该去自习看看ARC的注意事项和Block的使用了
// AFNetworking的写法
__weak __typeof(&*self)weakSelf = self;
// 我之前一直这么写的
__weak __typeof(self) weakSelf = self;
// 或者这么写
__weak XxxViewController *weakSelf = self;
// 或者这么写
__weak id weakSelf = self;
这四种写法居然都是对的,第三种在我看来是最不好的,因为每个地方都要单独写。而其余几种写法都可以封装成一个宏,当项目中很多地方都要写类似代码时,用宏肯定是最佳的实践。