前言
优化项目时检查到内存泄漏问题,是在 Block 中使用成员变量不当引起的。
问题
ViewController 中定义成员变量如下:
@implementation EHISalesLeadsListViewController {
__block NSString *pageNum;
}
使用如下:
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
pageNum = @"1";
}];
在这里,该 ViewController 消失时并没有走 dealloc 释放。
解决
1. 成员变量和属性
先了解下成员变量和属性的区别:
成员变量和属性都是 self 引用的变量。
成员变量:一般直接使用,不需要使用
self
引用(也可以使用self->
引用);
属性:一般都使用self.
引用(也可以使用下划线_
);
所以在 Block 中,属性一般会保持习惯使用 self.
引用,而成员变量容易忘记使用 self->
引用。
对于
block
使用成员变量、属性变量、self
来说,block
内部是直接强引用self
的。
(参考 block 解析 - 内存)
因为成员变量比属性变量更容易忽略 self
的引用,所以在 block
中更容易犯循环引用的错。在此着重建议使用成员变量的时候注意一下在 Block 中的使用。同时也比较 推荐使用属性。
2. 在 Block 中使用成员变量
对于 block
使用成员变量、属性变量、self
来说,block
内部是直接强引用 self
的。
在上面,因为 self
强引用 tableView
,tableView
强引用 Block
,Block
内使用 self
的成员变量 pageNum
。鉴于上面这句话,因此代码中虽然没有写 self->
引用,也会已经强引用 self
了。因为都是强引用,三者形成循环引用,内存泄露。
所以,我们要打破循环引用。
2.1 weakSelf
打破循环引用要使其中一方为 weak
弱引用,通常我们会在 Block
外先把 self
weak
掉,再在内部使用,如下:
@weakify(self)
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
@strongify(self)
self->pageNum = @"1";
}];
2.2 声明__block 修饰
可以使用 __weak
指向成员变量解决循环引用,也可以使用 __block
来解决。因为这里要修改变量的值,所以只能使用 __block
:
__block NSInteger blockPageIndex = pageIndex;
self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
blockPageIndex ++;
}];
3. 成员变量是否声明 __block 并没有影响
@implementation EHISalesLeadsListViewController {
__block NSString *pageNum;
}
前面在声明成员变量的时候使用 __block
修饰了,经过试验,完全没有作用,没有影响。
(参考 block 解析 - 内存)
参考
推荐
Block 的知识点的文章大家应该都看过,但是一不小心还是容易忽略犯错,所以在这里提供链接,多看多巩固吧。
该博客写的很好,还提供了一个 Block 小测验~
- ARC 下内存泄露的那些点 // 强烈推荐
顺便看到了一篇整理 ARC 下内存泄漏的文章,不仅是 Block ,通知、定时器等也会一不小心造成循环引用,导致内存泄漏。有些问题很隐秘,可能出了错查了半天都找不到自己问题到底在哪里了,所以多看看攒攒经验吧,遇到的时候就能吸取他人经验,避免一番苦工了。
网友评论