我们经常在block使用中碰到:capturing 'self' strongly in this block is likely to lead to a retain cycle
重要法则:
block对于其变量都会形成强引用(retain),对于self也会形成强引用(retain),而如果self本身对block也是强引用的话,就会形成强引用循环,无法释放——造成内存泄露。
1)self会对自己的属性或函数进行持有。
2)block主函数体,用到了self所拥有的任何东西(self、self.属性、[self 函数] ),block就会对self进行持有。
3)如果1、2情况同时存在,就会出现retain cycle问题。因为1很难做出改变,所以解决方法是对2进行改进。

如何避免?

1、简单判断:我一般重写dealloc方法,查看dealloc方法是否调用来判断是否有循环引用。
2、深层分析:根据上面法则来分析代码。
1、被block引用的变量都会被自动retain一次,这样的话至少可以保证我们的调用是有效的。因为block中的retain是隐式的,所以极易出现retain cycle的问题。
2、retain cycle,翻译成中文大概叫保留环吧。比如A和B两个对象,A持有B,B同时也持有A,A只有B释放之后才有可能释放,同样B只有A释放后才可能释放。当双方都在等待对方释放的时候, retain cycle就形成了。结果是,两个对象都永远不会被释放,最终内存泄露。
3、__strong: 赋值给这个变量的对象会自动被retain一次,如果在block中引用它,block也会retain它一次。
4、__unsafe_unretained: 赋值给这个变量不会被retain,也就是说被他修饰的变量的存在不能保证持有对象的可靠性,它可能已经被释放了,而且留下了一个不安全的指针。不会被block retain。 
5、__weak:类似于__unsafe_unretained,只是如果所持有的对象被释放后,变量会自动被设置为nil,这样更安全些,不过只在IOS5.0以上的系统支持,同样不会被block retain。
6、__block: 表示这个变量值能在block中被修改(值修改,而不是修改对象中的某一个属性,可以理解为修改指针的指向)。会被自动retain。
被 __block 修饰的变量在块中保存的是变量的地址。(其他为变量的值)
使用__weak打破循环的方法只在ARC下才有效,在MRC下应该使用__block
先用代码描述一下症状:
[objc] view plain copy
  1. /* ViewController.h */
  2. #import <UIKit/UIKit.h>
  3. typedef void (^ABlock)(void); //定义一个简单的Block
  4. @interface ViewController : UIViewController {
  5. // self的属性
  6. NSMutableArray *_items;
  7. // 1、self的属性,换句话说,self持有block,即self对block具有强引用
  8. ABlock _block;
  9. }
  10. @end
  11. /* ViewController.m */
  12. #import "ViewController.h"
  13. @implementation ViewController
  14. - (void)viewDidLoad
  15. {
  16. [super viewDidLoad];
  17. _items = [[NSMutableArray alloc] init];
  18. _block = ^{
  19. // 2、_block内部用到了self的属性_items,换句话说,_block持有了self,导致retain cycle。
  20. // 因为只要 block中用到了对象的属性或者函数,block就会持有该对象而不是该对象中的某个属性或者函数。
  21. [_items addObject:@"Hello!"];
  22. };
  23. }
  24. @end

Xcode在编译以上程序的时候会给出一个警告:Captureing ‘self’ strongly in this block is likely to lead to a retain cycle。

原因:_items实际上是self->items。_block对象在创建的时候会被retain一次,因此会导致self也被retain一次。这样就形成了一个retain cycle。
解决方法:创建一个本地变量blockSelf,指向self,然后用结构体语法访问实例变量。代码如下:

[objc] view plain copy
  1. __block ViewController *blockSelf = self;
  2. _block = ^{
  3. [blockSelf->_items addObject:@"Hello!"];
  4. };

这么修改之后,blockSelf是本地变量,是弱引用,因此在_block被retain的时候,并不会增加retain count,所以retain cycle就解除了,Xcode也不再出现警告了,问题解决。

例子2:
[objc] view plain copy
  1. DoSomethingManager *manager = [[DoSomethingManager alloc] init];
  2. manager.complete = ^{
  3. [manager otherAction];
  4. [manager release];
  5. };

retain cycle 就这么形成了,即使调用了release,manager也不会释放,因为manager和block相互持有了。为了解除retain cycle的话,我们可以这样写:

[objc] view plain copy
  1. __block DoSomethingManager *manager = [[DoSomethingManager alloc] init];
  2. __weak DoSomethingManager *weakmanager = manager;
  3. manager.complete = ^{
  4. [weakmanager otherAction];
  5. };

iOS之Block报错:capturing 'self' strongly in this block is likely to lead to a retain cycle相关推荐

  1. ISE MAP报错: Unsupported programming for BSCAN block and JTAG_CHAIN attribute value 1的解决方法

    ISE MAP报错: Unsupported programming for BSCAN block and JTAG_CHAIN attribute value 1的解决方法 参考文章: (1)IS ...

  2. 以太坊搭建,不能使用puppeth 创建初始块,报错Fatal: Failed to write genesis block: unsupported fork ordering: eip15

    以太坊搭建,不能使用puppeth 创建初始块,报错Fatal: Failed to write genesis block: unsupported fork ordering: eip15 新建 ...

  3. Capturing 'self' strongly in this block is likely to lead to a retain cycle

    技术分享 » Phone | 阅读(1629) | 评论(0) May 10 2014 _player.completionBlock = ^{             [self stopPlay] ...

  4. ISE MAP报错: Unsupported programming for BSCAN block and JTAG_CHAIN attribute value 1的解决方法...

    2014-04-16 17:35:30 ISE MAP报错: Unsupported programming for BSCAN block and JTAG_CHAIN attribute valu ...

  5. ionic ios查看大图报错 the file to show is not valid image,or could not be loaded

    ionic ios查看大图报错 the file to show is not valid image,or could not be loaded 解决代码如下 public showImage(u ...

  6. xx.xib: error: Illegal Configuration: Safe Area Layout Guide before iOS 9.0报错问题解决

    之前是用xcode8.3.3创建的工程最近升级到Xcode9.0 遇见了这个问题 在Xcode 9.0以上 新建xib文件会报错 xx.xib: error: Illegal Configuratio ...

  7. python 报错 IndentationError: expected an indented block SyntaxError: invalid character in identifie

    红色方框那里敲击一个空格就好! 输入要在全英情况下! 另外,还要注意括号的事情.括号别出错误! IndentationError: expected an indented block的报错: Syn ...

  8. 【错误记录】发布 Flutter 插件包报错 ( It‘s strongly recommended to include a “homepage“ or “repository“ field )

    文章目录 一.报错信息 二.解决方案 一.报错信息 发布 Flutter 插件包到中央仓库前 , 先执行 flutter packages pub publish --dry-run 命令 , 检查插 ...

  9. Spark报错:Bad response ERROR for block BP-78092257-8.xx-121xxx

    1.背景 一个spark 运行了一夜的程序突然报错 java.io.Exception : Bad response ERROR for block BP-78092257-8.xx-121xxx:b ...

  10. iOS模拟器运行报错Unable to install /xxx/build/ios/iphonesimulator/Runner.app

    前言 最近在做项目用模拟器运行,清理缓存后发现模拟器运行不起来了,报错如下: Unable to install /xxx/build/ios/iphonesimulator/Runner.app o ...

最新文章

  1. HDOJ 1070 排序 水
  2. 百米路由器2登陆地址_女孩子也要会的无线路由器连接技巧,再也不求男生了...
  3. ViewPager实现页面切换
  4. html鼠标点击有手势出来,用原生js+css3撸的一个下拉手势事件插件
  5. mac os 录屏快捷键_Mac跨平台自动同步记事本
  6. mysql 学习笔记09字符串相关函数
  7. CodeForces 895 B. XK Segments 二分查找
  8. CocoaPods 错误 target overrides the `OTHER_LDFLAGS`...
  9. 经典算法排序——插入排序
  10. 公交/地铁出行测试点
  11. Samba安装详细步骤
  12. 疫情下跨越一万公里的友情:熊超与飒特电子哨兵的故事
  13. 211计算机考研到985难度,普通人想考研到985/211院校到底有多难?听听他们的心声!...
  14. 调研了700多家上市公司后,我们得聊聊“韧性”这件事
  15. 问题解决:Invalid version number:Version number may be negative or greater than 255
  16. Android扭曲图像(水面落叶壁纸初步实现)
  17. 论文中的参考文献规范
  18. QT窗口:透明与半透明、不规则异形窗口、控件透明与半透明、不规则异形按钮
  19. 不懂英语学计算机编程,不懂英语应该怎么学编程
  20. composer [InvalidArgumentException] Could not find package laravel/laravel with stability stable.

热门文章

  1. Entry name ‘META-INF/xxx‘ collided报错
  2. 功夫熊猫里乌龟大师的一句名言
  3. 移植实时操作系统到 risc-v 架构芯片时上下文切换的实现
  4. 让你更好使用 Typescript 的11个技巧
  5. angular-----Activated路由
  6. 计算机考研复试-计算机组成原理
  7. 史上最全面聊天机器人总结(图灵、思知、小i、小微)
  8. 信用卡上了“灰名单”怎么办?如何解除?
  9. 有利网2022最新兑付消息,开展部分债务资金清退
  10. RK3399调试支持以太网