iOS: ARC和非ARC下使用Block属性的问题
1. Block的声明和线程安全
Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非ARC下返回Block)。
另一个需要注意的问题是关于线程安全,在声明Block属性时需要确认“在调用Block时另一个线程有没有可能去修改Block?”这个问题,如果确定不会有这种情况发生的话,那么Block属性声明可以用nonatomic。如果不肯定的话(通常情况是这样的),那么你首先需要声明Block属性为atomic,也就是先保证变量的原子性(Objective-C并没有强制规定指针读写的原子性,C#有)。
比如这样一个Block类型:
typedef void (^MyBlockType)(int);
属性声明:
@property (copy) MyBlockType myBlock;
这里ARC和非ARC声明都是一样的,当然注意在非ARC下要release Block。
但是,有了atomic来保证基本的原子性还是没有达到线程安全的,接着在调用时需要把Block先赋值给本地变量,以防止Block突然改变。因为如果不这样的话,即便是先判断了Block属性不为空,在调用之前,一旦另一个线程把Block属性设空了,程序就会crash,如下代码:
if (self.myBlock)
{
//此时,走到这里,self.myBlock可能被另一个线程改为空,造成crash
//注意:atomic只会确保myBlock的原子性,这种操作本身还是非线程安全的
self.myBlock(123);
}
所以正确的代码是(ARC):
MyBlockType block = self.myBlock;
//block现在是本地不可变的
if (block)
{
block(123);
}
在非ARC下则需要手动retain一下,否则如果属性被置空,本地变量就成了野指针了,如下代码:
//非ARC
MyBlockType block = [self.myBlock retain];
if (block)
{
block(123);
}
[block release];
2. 循环引用问题
循环引用是另一个使用Block时常见的问题。
在ARC下,由于__block抓取的变量一样会被Block retain,所以必须用弱引用才可以解决循环引用问题,iOS 5之后可以直接使用__weak,之前则只能使用__unsafe_unretained了,__unsafe_unretained缺点是指针释放后自己不会置空。示例代码:
//iOS 5之前可以用__unsafe_unretained
//__unsafe_unretained typeof(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
self.myBlock = ^(int paramInt)
{
//使用weakSelf访问self成员
[weakSelf anotherFunc];
};
在非ARC下,显然无法使用弱引用,这里就可以直接使用__block来修饰变量,它不会被Block所retain的,参考代码:
//非ARC
__block typeof(self) weakSelf = self;
self.myBlock = ^(int paramInt)
{
//使用weakSelf访问self成员
[weakSelf anotherFunc];
};
iOS: ARC和非ARC下使用Block属性的问题的更多相关文章
- IOS开发 ARC和非ARC下使用Block属性的问题
1. Block的声明和线程安全 Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非AR ...
- ios工程中ARC与非ARC的混合
ARC与非ARC在一个项目中同时使用, 1,选择项目中的Targets,选中你所要操作的Target,2,选Build Phases,在其中Complie Sources中选择需要ARC的文件双击,并 ...
- (转)iOS 开发,工程中混合使用 ARC 和非ARC
[前提知识] ARC:Automatic Reference Counting,自动引用计数 在开发 iOS 3 以及之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retain. ...
- IOS ARC和非ARC文件混用
ARC在SDK4.0的时候增加的,因为要和曾经的项目融合,就会有arc和非arc文件的混合. 当然,也就这两种情况: 1.自己的旧项目没有使用ARC,可是引入的第三方库却是使用了ARC的. 2.自己的 ...
- iOS 开发,工程中混合使用 ARC 和非ARC(转)
[前提知识] ARC:Automatic Reference Counting,自动引用计数 在开发 iOS 3 以及之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retain. ...
- iOS arc和非arc 适用 宏
iOS arc和非arc 适用 宏 1:使用宏 + (void)showAlertWithMessage:(NSString *)messages { dispatch_async(dispatch_ ...
- iOS 开发,混合使用 ARC 和非ARC
[前提知识] ARC:Automatic Reference Counting,自动引用计数 在开发 iOS 3 以及之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retain. ...
- iOS中ARC和非ARC混用
如果在使用第三方类库的时候,我们可能会遇到一些内存管理的问题 那么如何在一个工程中实现ARC和非ARC混用呢,例如你创建一个ARC的工程,但是你引用的第三方类库是非ARC管理内存的 首先点击工 ...
- ARC 与非 ARC 之间那些的'祸害'
你是否也曾被 assign.retain.copy.release.autorelease.strong.__strong.weak.__weak.__unsafe__unretain.__autor ...
随机推荐
- redis 参考
http://redis.readthedocs.org/en/2.4/index.html
- [java线段树]2015上海邀请赛 D Doom
题意:n个数 m个询问 每个询问[l, r]的和, 再把[l, r]之间所有的数变为平方(模为9223372034707292160LL) 很明显的线段树 看到这个模(LLONG_MAX为922337 ...
- C/C++语言参数传递----函数/方法 参数的指针引用传递
int m_value = 1; void func(int *p) { p = &m_value; } int main(int argc, char *argv[]) { int n = ...
- c++ 基础学习: 左值 概念cocos2d-x3.0的实际应用
左值:概念baidu 1.2.6.2 与Cocos2d-x内存管理的结合 在2.x的使用场景中,CCArray和CCDictionary通常被分配在堆上,我们不得不需要考虑在适当的地方释放其内存.新的 ...
- Android:使用ViewPager实现左右滑动切换图片 (简单版)
ViewPager,它是google SDk中自带的一个附加包的一个类, 可以使视图滑动. 步骤: 1.引入android-support-v4.jar包,在主布局里加入 <android.su ...
- linux非阻塞的socket EAGAIN的错误处理
http://blog.csdn.net/tianmohust/article/details/8691644 在Linux中使用非阻塞的socket的情形下. (一)发送时 当客户通过Socket提 ...
- 【转】Ubuntu乱码解决方案(全)
转自:http://www.cnblogs.com/end/archive/2011/04/19/2021507.html ubuntu下中文乱码解决方案(全) 1.ibus输入法 Ubuntu 系统 ...
- Webform——内嵌word编辑器
word编辑器,类似于Word的. 首先需要添加两个引用: 然后把一个文件夹仍在根目录下: 继而在工具箱里 选择项→浏览找到这两个引用,直接把工具拽进来就行: 获取编辑器文本: protected v ...
- redis作为mysql的缓存服务器(读写分离,通过mysql触发器实现数据同步)
一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录 ...
- apache开源项目--Camel
Apache Camel 是一个非常强大的基于规则的路由以及媒介引擎,该引擎提供了一个基于POJO的 企业应用模式(Enterprise Integration Patterns)的实现,你可以采用其 ...