block内部引用外界对象的原则:block会对他内部所有的强指针进行强引用。

验证原理:

在主控制器中modal出ModalVC控制器,ModalVC中有强引用的block属性,在block内部使用self,此时ModalVC便不会被释放,不会执行dealloc方法。

验证代码:

循环引用的情况:

  1. #import "ModalVC.h"
  2. @interface ModalVC ()
  3. // block属性
  4. @property (nonatomic, strong) void(^block)();
  5. @end
  6. @implementation ModalVC
  7. - (void)viewDidLoad {
  8. [super viewDidLoad];
  9. self.view.backgroundColor = [UIColor orangeColor];
  10. // 定义block属性
  11. self.block = ^{
  12. NSLog(@"%@", self);
  13. };
  14. // 调用block
  15. self.block();
  16. }
  17. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  18. // 返会上一层控制器
  19. [self dismissViewControllerAnimated:YES completion:nil];
  20. }
  21. - (void)dealloc {
  22. NSLog(@"ModalVC is release");
  23. }
  24. @end

改进方法: 将创建一个弱引用的self,供block内部使用

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.view.backgroundColor = [UIColor orangeColor];
  4. // 创建弱引用的self
  5. __weak typeof(self) weakSelf = self;
  6. // 定义block属性
  7. self.block = ^{
  8. NSLog(@"%@", weakSelf);
  9. };
  10. // 调用block
  11. self.block();
  12. }

block在多线程中问题

block中使用的对象可能会被提前释放。
  1. #import "ModalVC.h"
  2. @interface ModalVC ()
  3. // block属性
  4. @property (nonatomic, strong) void(^block)();
  5. @end
  6. @implementation ModalVC
  7. - (void)viewDidLoad {
  8. [super viewDidLoad];
  9. self.view.backgroundColor = [UIColor orangeColor];
  10. // 创建弱引用的self
  11. __weak typeof(self) weakSelf = self;
  12. // 定义block属性
  13. self.block = ^{
  14. // 延时执行
  15. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  16. NSLog(@"%@", weakSelf);
  17. });
  18. };
  19. // 调用block
  20. self.block();
  21. }
  22. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  23. // 返会上一层控制器
  24. [self dismissViewControllerAnimated:YES completion:nil];
  25. }
  26. - (void)dealloc {
  27. NSLog(@"ModalVC is release");
  28. }
  29. @end

在此种情况下,在ModalVC被modal出来后立即点击屏幕,打印结如下,说明ModalVC在延时中的block执行时已经被提前释放了,这种情况并不是我们想要的。

  1. 2016-01-16 10:06:19.206 004-block的循环引用问题[1863:54052] ModalVC is release
  2. 2016-01-16 10:06:19.547 004-block的循环引用问题[1863:54052] (null)

内存分析

当ModalVC被VC控制器modal出来时,它被VC的presentedViewController属性强引用,当点击屏幕时,ModalVC控制器被dismiss掉了,presentedViewController强指针就无效了,ModalVC因为没有强指针指向,就会被释放掉,block也会被释放掉,但是dispatch_after中的Block并没有被释放(被系统强引用着),两秒后执行时打印出的weakSelf就为nil。

解决方法:

在block对象中再对weakSelf增加一个强指针

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.view.backgroundColor = [UIColor orangeColor];
  4. // 创建弱引用的self
  5. __weak typeof(self) weakSelf = self;
  6. // 定义block属性
  7. self.block = ^{
  8. // 给weakSelf增加一个强指针
  9. __strong typeof(self) strongSelf = weakSelf;
  10. // 延时两秒
  11. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  12. NSLog(@"%@", strongSelf);
  13. });
  14. };
  15. // 调用block
  16. self.block();
  17. }

执行结果, 先打印ModalVC控制器,再释放ModalVC控制器

  1. 2016-01-16 10:57:16.837 004-block的循环引用问题[2113:80213] <ModalVC: 0x7fdcd1d26850>
  2. 2016-01-16 10:57:16.838 004-block的循环引用问题[2113:80213] ModalVC is release

内存分析

当点击屏幕时,ModalVC控制器被dismiss掉了,presentedViewController强指针就无效了,但是ModalVC控制器仍然会被dispatch_after中block的strongSelf所强引用,所以不会被释放掉。

block之---循环引用的更多相关文章

  1. 避免Block的循环引用

    避免Block的循环引用 什么是循环引用,什么时候发生循环引用 1 循环引用就是当self 拥有一个block的时候,在block 又调用self的方法.形成你中有我,我中有你,谁都无法将谁释放的困局 ...

  2. 关于block的循环引用的问题

    在block的循环引用的问题上我们都知道如果在block内部修改外部的变量的时候,要加__block以防止循环引用的问题,但是如果block是当前对象的一个属性的时候,要修改当前对象的一个属性的时候就 ...

  3. iOS开发Block的介绍以及Block的循环引用问题

    1:block的循环引用问题最主要记住两点: 如果[block内部]使用[外部声明的强引用]访问[对象A], 那么[block内部]会自动产生一个[强引用]指向[对象A] 如果[block内部]使用[ ...

  4. block的循环引用

    什么是循环引用呢? 就是我引用你,你引用我,就会造成循环引用,双方都不会被销毁,导致内存泄漏. _block =  ^{ NSLog(@"%@", self); }; block会 ...

  5. weakSelf 运用 strongSelf来解决block的循环引用

    SDWebImage 中有一段源码: #if SD_UIKIT Class UIApplicationClass = NSClassFromString(@"UIApplication&qu ...

  6. iOS - Block的循环引用内存泄漏问题探索

    循环引用的原因 众所周知,ARC下用block会产生循环引用的问题,造成泄露的原因是啥呢? 最简单的例子,如下面代码: [self.teacher requestData:^(NSData *data ...

  7. 避免在block中循环引用(Retain Cycle in Block)

    让我们长话短说.请参阅如下代码: - (IBAction)didTapUploadButton:(id)sender { NSString *clientID = @"YOUR_CLIENT ...

  8. iOS开发小技巧--键盘处理以及解决block造成循环引用的小技巧

  9. block使用小结、在arc中使用block、如何防止循环引用

    引言 使用block已经有一段时间了,感觉自己了解的还行,但是几天前看到CocoaChina上一个关于block的小测试主题: [小测试]你真的知道blocks在Objective-C中是怎么工作的吗 ...

随机推荐

  1. ZOJ 3927 Programming Ability Test

    水题,判断一下加起来是否大于等于80 #include<cstdio> #include<cstring> #include<cmath> #include< ...

  2. HUST 1371 Emergency relief

    状态压缩. 每一个人所需的物品对应一个数字,统计一个每个数字有几个.每一种提供物品的状态也对应一个数字,然后暴力判断. #include<cstdio> #include<cstri ...

  3. CodeForces 626D Jerry's Protest

    计算前两盘A赢,最后一盘B赢的情况下,B获得的球的值总和大于A获得的球总和值的概率. 存储每一对球的差值有几个,然后处理一下前缀和,暴力枚举就好了...... #include<cstdio&g ...

  4. 初学杂文 String类

    String: 两个字符床  String stra 和String strb stra = "hello " ; strb = "hello " 在对象池中开 ...

  5. java web开发中的奇葩事web.xml中context-param中的注释

    同事提交了代码.结果除同事之外,其他人全部编译报错.报错说web.xml中配置的一个bean 没有定义.按照报错提示,各种找,无果. 由于代码全部都是提交到svn主干,之前也没有做过备份,只能一步一步 ...

  6. OpenSceneGraph几个重要功能节点练习

    OpenSceneGraph几个重要功能节点练习 一. 空间变换节点 空间变换中最重要的是坐标系和矩阵运算了.OSG坐标系中使用右手系,Z轴垂直向上,X轴水平向右,Y轴垂直屏幕向里,与OpenGL和D ...

  7. Android与Linux以及GNU的关系

    转帖自 http://www.eefocus.com/Kevin/blog/09-11/179409_1dc9a.html 作者: Kevin 本文转贴自 http://mmdays.com/2008 ...

  8. 安卓版php服务器的mysql数据库增删改查简单案例

    界面: index.php文件: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "h ...

  9. 2. 托管对象数据模型的基本知识(Core Data 应用程序实践指南)

    第一章的例子配置好了持久化存储区.持久化存储协调器.托管对象上下文.但是还没有对象图,本章要介绍托管对象模型的基础知识,并配置范例程序的对象图. 2.1. 托管对象模型是什么 托管对象模型是一种数据结 ...

  10. @RequestBody和@ResponseBody

    @RequestBody 将HTTP请求正文转换为适合的HttpMessageConverter对象. @ResponseBody 将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMess ...