下面评论的好友“@Jim”给了种新的思路,就是在清除context的函数里面,用“_bridge_transfer”转换context,把context的内存管理权限重新交给ARC,这样,就不用显式调用“CFRelease”了。如下:
1
|
void cleanStaff(void *context) {
|
看过GCD(Grand Central Dispatch)的Apple官方文档的朋友一定见过“dispatch_set_context”和“dispatch_get_context”这两个函数,那么这两个函数该怎么用呢?
我们都知道,GCD的接口参数都是“C语言类型“的,那么,我们如何将NSObject类型(Foundation框架)的数据,传入GCD的接口呢?(即:Core Foundation和Foundation对象的转换)
先看看这两个函数的原型:
1
|
//设置context
|
这里的object一般指的就是通过dispatch_queue_create创建的队列。
所以,这两个函数分别完成了将context“绑定”到特定GCD队列和从GCD队列获取对应context的任务。
在上述函数原型中,context是一个“void类型指针”,学过C语言的朋友应该都知道,void型指针可以指向任意类型,就是说,context在这里可以是任意类型的指针。
从这里可以得知,我们可以为队列“set”任意类型的数据,并在合适的时候取出来用。
参考Apple官方的例子,我们先用传统的malloc创建context,看看如下简短例子:
1
|
//定义context,即一个结构体
|
上面的代码运行后如下:
1
|
2015-03-29 20:28:16.854 GCDTest[37787:1443423] 1: context number: 10
|
看,通过为队列设置context,我们就能为队列绑定自定义的数据,然后在合适的时候取出来用。
在Mac、iOS的开发过程中,我们大部分用的都是Foundation框架下的类,就是如NSString、NSDictionary这些NSObject类型的类。
但是上面的dispatch_set(get)_context接受的context参数是C语言类型的,即Core Foundation类型的,我们如何转换呢?
由于ARC不能管理Core Foundation Object的生命周期,所以我们必须先转换context的“类型”,以便转换内存管理权。
Apple已经为我们提供了用于转换的关键字,如下:
为了方便下面的说明,我们先定义context类。
1
|
@interface Data : NSObject
|
看,我们继承了dealloc方法,这样就能知道Data类型对象什么时候被释放。
__bridge的转换是没有转移内存管理权的,这点要特别注意。
如果在传context对象时,用的是__bridge转换,那么context对象的内存管理权还在ARC手里,一旦当前作用域执行完,context就会被释放,而如果队列的任务用了context对象,就会造成“EXC_BAD_ACCESS”崩溃!
重写上面的例子,如下:
1
|
//定义队列的finalizer函数,用于释放context内存
|
1
|
2015-03-29 21:12:41.631 GCDTest[38131:1465900] 1: context number: 10
|
由结果可知,我们的context对象在最后显式调用CFRelease才被释放。
总的来说,就是合理运用__bridge_retained(transfer)关键字转换对象的内存管理权,让我们自己控制对象的生命周期。
为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权-备
原文:http://www.cnblogs.com/isItOk/p/5300712.html