block使用时的一些情况以及防止循环引用
block 是在 iOS 4 中引入的新特性,苹果官方推荐使用这种做法。
block 注意事项
1,block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝。
如下代码:
-(void)testVariable
{NSInteger outsideVariable = 10;//__block NSInteger outsideVariable = 10;NSMutableArray * outsideArray = [[NSMutableArray alloc] init];void (^blockObject)(void) = ^(void){NSInteger insideVariable = 20;NSLog(@" > member variable = %d", self.memberVariable);NSLog(@" > outside variable = %ld", (long)outsideVariable);NSLog(@" > inside variable = %ld", (long)insideVariable);[outsideArray addObject:@"AddedInsideBlock"];};outsideVariable = 30;self.memberVariable = 30;blockObject();NSLog(@" > %lu items in outsideArray", (unsigned long)[outsideArray count]);}
打印结果如下:
注意到outside 变量的输出值为10,这是因为blockObject 在实现时会对 outside 变量进行只读拷贝,在 block 块内使用该只读拷贝。因此这里输出的是拷贝时的变量值 10。如果,我们想要让 blockObject 修改或同步使用 outside 变量就需要用 __block 来修饰 outside 变量。
**注意**
a),在上面的 block 中,我们往 outsideArray 数组中添加了值,但并未修改 outsideArray 自身,这是允许的,因为拷贝的是 outsideArray 自身。
b),对于 static 变量,全局变量,在 block 中是有读写权限的,因为在 block 的内部实现中,拷贝的是指向这些变量的指针。
c), __block 变量的内部实现要复杂许多,__block 变量其实是一个结构体对象,拷贝的是指向该结构体对象的指针。
2 ,使用 weak–strong dance 技术来避免循环引用
在block中调用self很可能会引起循环引用,在block中需要对weakSelf进行strong,保证代码在执行到block中,self不会被释放,当block执行完后,会自动释放该strongSelf。
先看这个例子:
NSArray *anArray = @[@"1", @"2", @"3"];
[anArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {[self doSomething:idx];
}];
这种情况下,block中retain了self,当block中的代码被执行完后,self就会被ARC释放。所以不需要处理weakself的情况。
该VC被销毁后会有delloc打印。
再来看一个例子:
NSArray *anArray = @[@"1", @"2", @"3"];[anArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {[self dosomething:obj];}];
// __weak SecondViewController *weakself = self;self.aBlock = ^(id obj, NSUInteger idx, BOOL *stop){[self dosomething:obj];};
这种情况编译器会包警告提示这儿的self:
并且不会有delloc的打印。
这个例子的区别在于:block被self strong引用。所以结果就是block中引用了self,self引用了block。那么这个时候,如果你不使用weakself,则self和block永远都不会被释放。
那么是不是遇到block都要使用weakself呢?当然不是,而且如果全部使用weakself,会出现你想执行block中的代码时,self已经被释放掉了的情况。
另外,在处理weakself时,有两种做法:__weak和__unsafe_unretained。两种做法各有推荐,
还有一种比较常用的方法,这个方法比较通用:
/**
* 强弱引用转换,用于解决代码块(block)与强引用self之间的循环引用问题
* 调用方式: `@weakify_self`实现弱引用转换,`@strongify_self`实现强引用转换
*
* 示例:
* @weakify_self
* [obj block:^{
* @strongify_self
* self.property = something;
* }];
*/
#ifndef weakify_self
#if __has_feature(objc_arc)
#define weakify_self autoreleasepool{} __weak __typeof__(self) weakSelf = self;
#else
#define weakify_self autoreleasepool{} __block __typeof__(self) blockSelf = self;
#endif
#endif
#ifndef strongify_self
#if __has_feature(objc_arc)
#define strongify_self try{} @finally{} __typeof__(weakSelf) self = weakSelf;
#else
#define strongify_self try{} @finally{} __typeof__(blockSelf) self = blockSelf;
#endif
#endif
/**
* 强弱引用转换,用于解决代码块(block)与强引用对象之间的循环引用问题
* 调用方式: `@weakify(object)`实现弱引用转换,`@strongify(object)`实现强引用转换
用的时候就:
@weakify(self) 外部weak
@strongify(self) 内部strong
这样就避免了循环引用了,dealloc打印如下:
2016-05-18 11:36:31.531 lianxi[10219:1055254] *****
dealloc
No retain cycle
block使用时的一些情况以及防止循环引用相关推荐
- [js] 举例说明Object.defineProperty会在什么情况下造成循环引用导致栈溢出?
[js] 举例说明Object.defineProperty会在什么情况下造成循环引用导致栈溢出? var data = {count: 1,value: 2 } Object.definePrope ...
- iOS进阶之底层原理-block本质、block的签名、__block、如何避免循环引用
面试的时候,经常会问到block,学完本篇文章,搞通底层block的实现,那么都不是问题了. block的源码是在libclosure中. 我们带着问题来解析源码: blcok的本质是什么 block ...
- 问题1:UIView不会被释放--block中如果有self的话会造成循环引用
2019独角兽企业重金招聘Python工程师标准>>> 程序使用的是 UINavigationController . 使用tableView来显示对应的城市,在下载离线地图的时候, ...
- block(六)循环引用-b
在ARC与非ARC环境下对block使用不当都会引起循环引用问题,一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,简单说就是self.theBloc ...
- iOS开发笔记(二):block循环引用
写这篇文章的缘由是第一次面试时被问到了block循环引用的问题,当时回答的不是很好,首先要明确的是,block是否用copy修饰决定不了循环引用的产生,在此再一次进行补强,有不对的地方还请多多指教. ...
- Block循环引用问题(Objective-c)
造成循环引用的简单理解是:Block的拥有者在Block作用域内部又引用了自己,因此导致了Block的拥有者永远无法释放内存,就出现了循环引用的内存泄漏 示例代码 @interface ObjTest ...
- 有没搞错?Java 对象不使用时要赋值为 null?
点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 许多Java开发者都曾听说过"不使用的对象应手动赋 ...
- 场效应管的判别、检测及使用时的注意事项!
一.用指针式万用表对场效应管进行判别 1)用测电阻法判别结型场效应管的电极 根据场效应管的PN结正.反向电阻值不一样的现象,可以判别出结型场效应管的三个电极.具体方法:将万用表拨在R×1k档上,任选两 ...
- 有没有搞错?Java 对象不使用时,要赋值为 null?
来源 | olarxiong.com/category/java/ 前言 最近,听粉丝讨论说,"不使用的对象应手动赋值为null" 这句话,而且好多开发者一直信奉着这句话:问其原因 ...
最新文章
- 内网PC通过NAT server公网地址访问内部服务器时TCP三次握手不成功
- mysql触发器和存储过程_MySql的存储过程和触发器
- Python 技巧篇-同一个方法多次引用不同效果功能实现,可选参数设置方法
- 【收藏】Linux 运维必备的 40 个命令总结
- 【要闻】Kubernetes不适合发行版模式、Windows业务无法达到营收指引
- Dragonfly成为CNCF孵化项目,我们与基金会首位华人TOC聊了聊
- C语言1094题目,基于visual Studio2013解决C语言竞赛题之1094纵横图
- 小程序入门学习09--云开发02
- Python网络编程之socket
- atitit.groovy 语法特性
- IplImage 加载图像
- 央妈:银联,想说爱你不容易
- try with resource 的使用
- P9 力荐!阿里巴巴最新出品 776 页 JDK 源码 + 并发核心原理解析小册
- 幻灯片制作 新手制作幻灯片-来自于三人行慕课
- 关闭2345,搜狐等软件的弹窗
- 微信小程序云开发之云数据库
- 详细地址访问腾讯地图API,转换为经纬度
- Java爬虫实践:Jsoup+HttpUnit爬取今日头条、网易、搜狐、凤凰新闻
- 拥有一台云服务器可以干什么?