block之---循环引用
block内部引用外界对象的原则:block会对他内部所有的强指针进行强引用。
验证原理:
在主控制器中modal出ModalVC控制器,ModalVC中有强引用的block属性,在block内部使用self,此时ModalVC便不会被释放,不会执行dealloc方法。
验证代码:
循环引用的情况:
#import "ModalVC.h"
@interface ModalVC ()
// block属性
@property (nonatomic, strong) void(^block)();
@end
@implementation ModalVC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
// 定义block属性
self.block = ^{
NSLog(@"%@", self);
};
// 调用block
self.block();
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 返会上一层控制器
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)dealloc {
NSLog(@"ModalVC is release");
}
@end
改进方法: 将创建一个弱引用的self,供block内部使用
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
// 创建弱引用的self
__weak typeof(self) weakSelf = self;
// 定义block属性
self.block = ^{
NSLog(@"%@", weakSelf);
};
// 调用block
self.block();
}
block在多线程中问题
#import "ModalVC.h"
@interface ModalVC ()
// block属性
@property (nonatomic, strong) void(^block)();
@end
@implementation ModalVC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
// 创建弱引用的self
__weak typeof(self) weakSelf = self;
// 定义block属性
self.block = ^{
// 延时执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", weakSelf);
});
};
// 调用block
self.block();
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 返会上一层控制器
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)dealloc {
NSLog(@"ModalVC is release");
}
@end
在此种情况下,在ModalVC被modal出来后立即点击屏幕,打印结如下,说明ModalVC在延时中的block执行时已经被提前释放了,这种情况并不是我们想要的。
2016-01-16 10:06:19.206 004-block的循环引用问题[1863:54052] ModalVC is release
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增加一个强指针
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
// 创建弱引用的self
__weak typeof(self) weakSelf = self;
// 定义block属性
self.block = ^{
// 给weakSelf增加一个强指针
__strong typeof(self) strongSelf = weakSelf;
// 延时两秒
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", strongSelf);
});
};
// 调用block
self.block();
}
执行结果, 先打印ModalVC控制器,再释放ModalVC控制器
2016-01-16 10:57:16.837 004-block的循环引用问题[2113:80213] <ModalVC: 0x7fdcd1d26850>
2016-01-16 10:57:16.838 004-block的循环引用问题[2113:80213] ModalVC is release
内存分析
当点击屏幕时,ModalVC控制器被dismiss掉了,presentedViewController强指针就无效了,但是ModalVC控制器仍然会被dispatch_after中block的strongSelf所强引用,所以不会被释放掉。
block之---循环引用的更多相关文章
- 避免Block的循环引用
避免Block的循环引用 什么是循环引用,什么时候发生循环引用 1 循环引用就是当self 拥有一个block的时候,在block 又调用self的方法.形成你中有我,我中有你,谁都无法将谁释放的困局 ...
- 关于block的循环引用的问题
在block的循环引用的问题上我们都知道如果在block内部修改外部的变量的时候,要加__block以防止循环引用的问题,但是如果block是当前对象的一个属性的时候,要修改当前对象的一个属性的时候就 ...
- iOS开发Block的介绍以及Block的循环引用问题
1:block的循环引用问题最主要记住两点: 如果[block内部]使用[外部声明的强引用]访问[对象A], 那么[block内部]会自动产生一个[强引用]指向[对象A] 如果[block内部]使用[ ...
- block的循环引用
什么是循环引用呢? 就是我引用你,你引用我,就会造成循环引用,双方都不会被销毁,导致内存泄漏. _block = ^{ NSLog(@"%@", self); }; block会 ...
- weakSelf 运用 strongSelf来解决block的循环引用
SDWebImage 中有一段源码: #if SD_UIKIT Class UIApplicationClass = NSClassFromString(@"UIApplication&qu ...
- iOS - Block的循环引用内存泄漏问题探索
循环引用的原因 众所周知,ARC下用block会产生循环引用的问题,造成泄露的原因是啥呢? 最简单的例子,如下面代码: [self.teacher requestData:^(NSData *data ...
- 避免在block中循环引用(Retain Cycle in Block)
让我们长话短说.请参阅如下代码: - (IBAction)didTapUploadButton:(id)sender { NSString *clientID = @"YOUR_CLIENT ...
- iOS开发小技巧--键盘处理以及解决block造成循环引用的小技巧
- block使用小结、在arc中使用block、如何防止循环引用
引言 使用block已经有一段时间了,感觉自己了解的还行,但是几天前看到CocoaChina上一个关于block的小测试主题: [小测试]你真的知道blocks在Objective-C中是怎么工作的吗 ...
随机推荐
- webstrom命令大全
Ctrl + Space:Basic code completion (the name of any class, method or variable) 基本代码完成(任何类.函数或者变量名称), ...
- S3C2440串口及其中断系统详解
个独立异步串行I/O(SIO)端口,每个都可以是基于中断或基于DMA模式的操作.换句话说,UART可以通过产生中断或DMA请求来进行CPU和UART之间的数据传输. 字节的FIFO给发送和接收. 字节 ...
- linux 下source、sh、bash、./执行脚本的区别
原文地址:http://blog.csdn.net/caesarzou/article/details/7310201 source命令用法: source FileName 作用:在当前bash环境 ...
- Vim 第一天
记得第一次接触vi编辑器,好像是在海尔的机房吧,那是时候还是没有毕业的小菜鸟一只(PS:现在也是菜鸟),记得是测试一个云存储的产品.看着他们用vi编辑器,当时也没有感觉有什么(现在也没感觉……),只是 ...
- 使用(Drawable)资源———ClipDrawable资源
ClipDrawable代表从其他位图上截取的一个"图片片段".在XML文件中定义ClipDrawable对象使用<clip.../>元素,该元素的语法为: <? ...
- C++写时钟表
time函数的运用,输出是没输换行,在流中,就什么的输不出,可以用清流函数,fflush(stdout) 代码 #include<iostream>#include<cstdio&g ...
- HDU-2060-Snooker
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2060 题意: 给你场上剩下的球数m , 和 a ,b 两名队员目前得分,现在假设a将 所有的球m都打入 ...
- Unity基础学习-Unity概述
Unity 概述 Unity是一个强大的引擎,里面包括大量的工具用来满足各种各样的需求.Unity的编辑器是直观的可定制的,让您在您的工作流中有较大的自由度. 本小节是开始学习Unity的关键部分.里 ...
- #DP# ----- OpenJudge数字组合
OpenJudge 2985:数字组合 总时间限制:1000ms 内存限制: 65536kB 描述 有n个正整数,找出其中和为t(t也是正整数)的可能的组合方式.如:n=5,5个数分别为1,2,3, ...
- LazyInitializationException--由于session关闭引发的异常
1,页面中进行person.department.departmentName的读取 2,Action 中只读取了person,事务作用在Service的方法中 3,后台会有org.hibernate ...