为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权-备
下面评论的好友“@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对象的转换)
本文关键字
- GCD:dispatch_set_context,dispatch_get_context
- __bridge,__bridge_retained,__bridge_transfer
- Core Foundation, NSObject
dispatch_set(get)_context
先看看这两个函数的原型:
1 |
//设置context |
这里的object一般指的就是通过dispatch_queue_create创建的队列。
所以,这两个函数分别完成了将context“绑定”到特定GCD队列和从GCD队列获取对应context的任务。
什么是context
在上述函数原型中,context是一个“void类型指针”,学过C语言的朋友应该都知道,void型指针可以指向任意类型,就是说,context在这里可以是任意类型的指针。
从这里可以得知,我们可以为队列“set”任意类型的数据,并在合适的时候取出来用。
用malloc创建context并绑定到队列上
参考Apple官方的例子,我们先用传统的malloc创建context,看看如下简短例子:
1 |
//定义context,即一个结构体 |
上面的代码运行后如下:
1 |
2015-03-29 20:28:16.854 GCDTest[37787:1443423] 1: context number: 10 |
看,通过为队列设置context,我们就能为队列绑定自定义的数据,然后在合适的时候取出来用。
NSObject类型的context
在Mac、iOS的开发过程中,我们大部分用的都是Foundation框架下的类,就是如NSString、NSDictionary这些NSObject类型的类。
但是上面的dispatch_set(get)_context接受的context参数是C语言类型的,即Core Foundation类型的,我们如何转换呢?
由于ARC不能管理Core Foundation Object的生命周期,所以我们必须先转换context的“类型”,以便转换内存管理权。
__bridge
Apple已经为我们提供了用于转换的关键字,如下:
- __bridge: 只做了类型转换,不修改内存管理权;
- __bridge_retained(即CFBridgingRetain)转换类型,同时将内存管理权从ARC中移除,后面需要使用CFRelease来释放对象;
- __bridge_transfer(即CFBridgingRelease)将Core Foundation的对象转换为Objective-C的对象,同时将内存管理权交给ARC。
重新定义context
为了方便下面的说明,我们先定义context类。
1 |
@interface Data : NSObject |
看,我们继承了dealloc方法,这样就能知道Data类型对象什么时候被释放。
需要注意的点
__bridge的转换是没有转移内存管理权的,这点要特别注意。
如果在传context对象时,用的是__bridge转换,那么context对象的内存管理权还在ARC手里,一旦当前作用域执行完,context就会被释放,而如果队列的任务用了context对象,就会造成“EXC_BAD_ACCESS”崩溃!
正确的用法
重写上面的例子,如下:
1 |
//定义队列的finalizer函数,用于释放context内存 |
解释
- 在dispatch_set_context的时候用__bridge_retained转换,将context的内存管理权从ARC移除,交给我们自己管理。
- 在队列任务中,用dispatch_get_context获取context的时候,用__bridge转换,维持context的内存管理权不变,防止出了作用域context被释放。
- 最后用CFRelease释放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)转移内存管理权-备的更多相关文章
- 将如下三组不同类型的数据利用DataInputStream和DataOutputStream写入文件,然后从文件中读出
三组数据如下: {19.99 , 9.99 , 15.99 , 3.99 , 4.99} {12 , 8 , 13 ,29 ,50} {"Java T-shirt" , " ...
- springMVC参数绑定JSON类型的数据
需求就是: 现在保存一个Student,并且保存Student的friend,一个student会有多个朋友,这里要传递到后台的参数是: var friends = new Array(); var ...
- GCD使用经验与技巧浅谈
前言 GCD(Grand Central Dispatch)可以说是Mac.iOS开发中的一大“利器”,本文就总结一些有关使用GCD的经验与技巧. dispatch_once_t必须是全局或stati ...
- 唐巧的iOS技术博客选摘
1. 那些被遗漏的objective-c保留字:http://blog.devtang.com/blog/2013/04/29/the-missing-objc-keywords/ 2. 使用cr ...
- Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案
本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注.Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调 ...
- TreeView树形控件递归绑定数据库里的数据
TreeView树形控件递归绑定数据库里的数据. 第一种:性能不好 第一步:数据库中查出来的表,字段名分别为UNAME(显示名称),DID(关联数据),UTYPE(类型) 第二步:前台代码 <% ...
- iOS边练边学--GCD的基本使用、GCD各种队列、GCD线程间通信、GCD常用函数、GCD迭代以及GCD队列组
一.GCD的基本使用 <1>GCD简介 什么是GCD 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 GCD的优势 G ...
- Windows Phone 8初学者开发—第14部分:在运行时绑定到真实的数据
原文 Windows Phone 8初学者开发—第14部分:在运行时绑定到真实的数据 第14部分:在运行时绑定到真实的数据 原文地址: http://channel9.msdn.com/Series/ ...
- 学习笔记TF049:TensorFlow 模型存储加载、队列线程、加载数据、自定义操作
生成检查点文件(chekpoint file),扩展名.ckpt,tf.train.Saver对象调用Saver.save()生成.包含权重和其他程序定义变量,不包含图结构.另一程序使用,需要重新创建 ...
随机推荐
- PL/SQL 包头和包体
包用于逻辑组合相关的过程和函数,它由包规范和包体两部分组成,包规范用于定义公用的常量 变量,过程和函数,在SQL*PLUS中建立包规范可以使用CREATE PACKAGE命令. 实例如下: CREAT ...
- Linux企业级项目实践之网络爬虫(27)——多路IO复用
与多线程和多进程相比,I/O多路复用的最大优势是系统开销小,系统不需要建立新的进程或者线程,也不必维护这些线程和进程. 主要应用: (1)客户程序需要同时处理交互式的输入和服务器之间的网络连接 (2) ...
- HDU_2055——刷题不要使用fflush()
Problem Description we define f(A) = 1, f(a) = -1, f(B) = 2, f(b) = -2, ... f(Z) = 26, f(z) = -26; G ...
- Linux下的bc计算器
bc = basic calculator scale:设置精度,默认为0 obase:设置输出进制,默认为10 ibase:设置输入进制,默认为10 原文:http://www.linuxidc.c ...
- ubuntu 创建eclipse 快捷方式
Ubuntu 上链接快捷方式,将想面内容复制并修改,命名为:eclipse.desktop #!/usr/bin/env xdg-open [Desktop Entry] Name=Eclipse C ...
- structured sparsity model
Data representation往往基于如下最小化问题: (1) 其中X是观测到的数据的特征矩阵,D是字典,Z是字典上的描述.约束项和使得字典dictionary和描述code具 ...
- MySQL 加密/压缩函数
这些问题可能导致数据值的改变.一般而言,上述问题可能在你使用非二进制串数据类型(如char,varchar,text等数据类型)的情况下发生. AES_ENCRYPT()和AES_DECRYPT() ...
- Linux中/etc/passwd文件与/etc/shadow文件解析.
此文章转载自"慧可",用来学习. 1. /etc/passwd文件 1.1 /etc/passwd文件内容格式 用户名: 密码 : uid : gid :用户描述:主目录:登陆s ...
- Python序列的方法(转)
在快速教程中,我们了解了最基本的序列(sequence).回忆一下,序列包含有定值表(tuple)和表(list).此外,字符串(string)是一种特殊的定值表.表的元素可以更改,定值表一旦建立,其 ...
- 服务 通话录音 TelephonyManager
MainActivity public class MainActivity extends ListActivity { private BatteryChangedReceiver rec ...