Core Foundation 框架
Core Foundation框架 (CoreFoundation.framework) 是一组C语言接口,它们为iOS应用程序提供基本数据管理和服务功能。下面列举该框架支持进行管理的数据以及可提供的服务:

群体数据类型 (数组、集合等)
程序包
字符串管理
日期和时间管理
原始数据块管理
偏好管理
URL及数据流操作
线程和RunLoop
端口和soket通讯
Core Foundation框架和Foundation框架紧密相关,它们为相同功能提供接口,但Foundation框架提供Objective-C接口。如果您将Foundation对象和Core Foundation类型掺杂使用,则可利用两个框架之间的 "toll-free bridging"。所谓的Toll-free bridging是说您可以在某个框架的方法或函数同时使用Core Foundatio和Foundation 框架中的某些类型。很多数据类型支持这一特性,其中包括群体和字符串数据类型。每个框架的类和类型描述都会对某个对象是否为 toll-free bridged,应和什么对象桥接进行说明。

如需进一步信息,请阅读Core Foundation 框架参考。

自 Xcode4.2 开始导入ARC机制后,为了支持对象间的转型,Apple又增加了许多转型用的关键字。这一讲我们就来了解其用法,以及产生的理由。

引子
我们先来看一下ARC无效的时候,我们写id类型转void*类型的写法:

id obj = [[NSObject alloc] init];
void *p = obj;
反过来,当把void*对象变回id类型时,只是简单地如下来写,

id obj = p;
[obj release];
但是上面的代码在ARC有效时,就有了下面的错误:

error: implicit conversion of an Objective-C pointer
        to 'void *' is disallowed with ARC
        void *p = obj;
                  ^
 
    error: implicit conversion of a non-Objective-C pointer
        type 'void *' to 'id' is disallowed with ARC
        id o = p;
                ^

__bridge
为了解决这一问题,我们使用 __bridge 关键字来实现id类型与void*类型的相互转换。看下面的例子。

id obj = [[NSObject alloc] init];
 
void *p = (__bridge void *)obj;
 
id o = (__bridge id)p;
将Objective-C的对象类型用 __bridge 转换为 void* 类型和使用 __unsafe_unretained 关键字修饰的变量是一样的。被代入对象的所有者需要明确对象生命周期的管理,不要出现异常访问的问题。

除过 __bridge 以外,还有两个 __bridge 相关的类型转换关键字:

__bridge_transfer
__bridge_retained
接下来,我们将看看这两个关键字的区别。

__bridge_retained
先来看使用 __bridge_retained 关键字的例子程序:

id obj = [[NSObject alloc] init];
 
void *p = (__bridge_retained void *)obj;
从名字上我们应该能理解其意义:类型被转换时,其对象的所有权也将被变换后变量所持有。如果不是ARC代码,类似下面的实现:

id obj = [[NSObject alloc] init];
 
void *p = obj;
[(id)p retain];
可以用一个实际的例子验证,对象所有权是否被持有。

void *p = 0;
 
{
    id obj = [[NSObject alloc] init];
    p = (__bridge_retained void *)obj;
}
 
NSLog(@"class=%@", [(__bridge id)p class]);
出了大括号的范围后,p 仍然指向一个有效的实体。说明他拥有该对象的所有权,该对象没有因为出其定义范围而被销毁。

__bridge_transfer
相反,当想把本来拥有对象所有权的变量,在类型转换后,让其释放原先所有权的时候,需要使用 __bridge_transfer 关键字。文字有点绕口,我们还是来看一段代码吧。

如果ARC无效的时候,我们可能需要写下面的代码。

// p 变量原先持有对象的所有权
id obj = (id)p;
[obj retain];
[(id)p release];
那么ARC有效后,我们可以用下面的代码来替换:

// p 变量原先持有对象的所有权
id obj = (__bridge_transfer id)p;
可以看出来,__bridge_retained 是编译器替我们做了 retain 操作,而 __bridge_transfer 是替我们做了 release1。

Toll-Free bridged
在iOS世界,主要有两种对象:Objective-C 对象和 Core Foundation 对象0。Core Foundation 对象主要是有C语言实现的 Core Foundation Framework 的对象,其中也有对象引用计数的概念,只是不是 Cocoa Framework::Foundation Framework 的 retain/release,而是自身的 CFRetain/CFRelease 接口。

这两种对象间可以互相转换和操作,不使用ARC的时候,单纯的用C原因的类型转换,不需要消耗CPU的资源,所以叫做 Toll-Free bridged。比如 NSArray和CFArrayRef, NSString和CFStringRef,他们虽然属于不同的 Framework,但是具有相同的对象结构,所以可以用标准C的类型转换。

比如不使用ARC时,我们用下面的代码:

NSString *string = [NSString stringWithFormat:...];
CFStringRef cfString = (CFStringRef)string;
同样,Core Foundation类型向Objective-C类型转换时,也是简单地用标准C的类型转换即可。

但是在ARC有效的情况下,将出现类似下面的编译错误:

Cast
of Objective-C pointer type 'NSString *' to C pointer type
'CFStringRef' (aka 'const struct __CFString *') requires a bridged cast
    Use __bridge to convert directly (no change in ownership)
    Use __bridge_retained to make an ARC object available as a +1 'CFStringRef' (aka 'const struct __CFString *')
错误中已经提示了我们需要怎样做:用 __bridge 或者 __bridge_retained 来转型,其差别就是变更对象的所有权。

正因为Objective-C是ARC管理的对象,而Core Foundation不是ARC管理的对象,所以才要特意这样转换,这与id类型向void*转换是一个概念。也就是说,当这两种类型(有ARC管理,没有ARC管理)在转换时,需要告诉编译器怎样处理对象的所有权。

上面的例子,使用 __bridge/__bridge_retained 后的代码如下:

NSString *string = [NSString stringWithFormat:...];
CFStringRef cfString = (__bridge CFStringRef)string;
只是单纯地执行了类型转换,没有进行所有权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。

NSString *string = [NSString stringWithFormat:...];
CFStringRef cfString = (__bridge_retained CFStringRef)string;
...
CFRelease(cfString); // 由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release
使用 __bridge_retained 可以通过转换目标处(cfString)的 retain 处理,来使所有权转移。即使 string 变量被释放,cfString 还是可以使用具体的对象。只是有一点,由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。

实际上,Core Foundation 内部,为了实现Core Foundation对象类型与Objective-C对象类型的相互转换,提供了下面的函数。

CFTypeRef  CFBridgingRetain(id  X)  {
    return  (__bridge_retained  CFTypeRef)X;
}
 
id  CFBridgingRelease(CFTypeRef  X)  {
    return  (__bridge_transfer  id)X;
}
所以,可以用 CFBridgingRetain 替代 __bridge_retained 关键字:

NSString *string = [NSString stringWithFormat:...];
CFStringRef cfString = CFBridgingRetain(string);
...
CFRelease(cfString); // 由于Core Foundation不在ARC管理范围内,所以需要主动release。
__bridge_transfer
所有权被转移的同时,被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会经常用到 __bridge_transfer 关键字。

CFStringRef cfString = CFStringCreate...();
NSString *string = (__bridge_transfer NSString *)cfString;
 
// CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权,所以不需要调用 release
同样,我们可以使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字。

CFStringRef cfString = CFStringCreate...();
NSString *string = CFBridgingRelease(cfString);

总结
由上面的学习我们了解到 ARC 中类型转换的用法,那么我们实际使用中按照怎样的原则或者方法来区分使用呢,下面我总结了几点关键要素。

明确被转换类型是否是 ARC 管理的对象
Core Foundation 对象类型不在 ARC 管理范畴内
Cocoa Framework::Foundation 对象类型(即一般使用到的Objectie-C对象类型)在 ARC 的管理范畴内
如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁
各种对象的生命周期是怎样的
1. 声明 id obj 的时候,其实是缺省的申明了一个 __strong 修饰的变量,所以编译器自动地加入了 retain 的处理,所以说 __bridge_transfer 关键字只为我们做了 release 处理。

__bridge,__bridge_transfer和__bridge_retained的使用和区别【转载】的更多相关文章

  1. apache与nginx日志文件的区别(转载)

    apache与nginx日志文件的区别 转载:http://www.xfcodes.com/apache/log/3270.htm 导读:apache与nginx日志文件的区别,在apache与ngi ...

  2. FB01与F-02的区别(转载)

    FB01与F-02的区别(转载) FB01 : a) ''Post Document'' b) No doc type as SA automatically comes. c) No automat ...

  3. SQL中select与set的区别-转载

    下表列出 SET 与 SELECT 的区别   SELECT SET 同时对多个变量同时赋值时 支持 不支持 表达式返回多个值时 将返回的最后一个值赋给变量 出错 表达式未返回值时 变量保持原值 变量 ...

  4. HTTP返回码中301与302的区别 (转载)

    一.官方说法 301,302 都是HTTP状态的编码,都代表着某个URL发生了转移,不同之处在于:  301 redirect: 301 代表永久性转移(Permanently Moved). 302 ...

  5. stdcall, cdecl, pascal 区别(转载)

    转载自:http://www.cnblogs.com/lidabo/archive/2012/11/21/2781484.html stdcall, cdecl, pascal 区别 这三个参数都是告 ...

  6. javascript:history.go()和History.back()的区别(转载)

    javascript:history.go()和History.back()的区别       <input type=button value=刷新 onclick="window. ...

  7. 表单中Readonly和Disabled的区别(转载)

    Readonly和Disabled是用在表单中的两个属性,它们都能够做到使用户不能够更改表单域中的内容.但是它们之间有着微小的差别,总结如下: Readonly只针对input(text / pass ...

  8. IIS7 经典模式和集成模式的区别(转载)

    转载地址:http://www.poluoluo.com/server/201301/193110.html 升级过程中出现了比较多的问题,前面文章也提到过几个.这次就主要介绍下httpHandler ...

  9. Minitab中相关系数R-Sq和修正R-Sq(adj)的意思,计算公式和区别[转载]

    转载自:http://www.pinzhi.org/thread-7762-1-1.html Minitab中相关系数R-Sq和修正的相关系数R-Sq(adj)的意思,计算公式和区别 在Minitab ...

随机推荐

  1. myeclipse 之 快捷键

    简单记录一下,新装了个机器,win7系统,想设置一下自己习惯的快捷键 如:ctrl+alt+方向键,复制行,发现设置不上,原先的自带的也失效,设置一下ctrl+alt+其它键,ok可以使用,这说明某些 ...

  2. Inno Setup入门(二十)——Inno Setup类参考(6)

    存储框 存储框也是典型的窗口可视化组件,同编辑框类似,可以输入.显示文本,但是和编辑框不同的是,编辑框只能编辑.显示单行文本,而存储框则可以对多行文本进行操作.存储框的类定义如下:< xmlna ...

  3. git 提高下载速度

    1.  直接下载分支,就不用下载不需要的源码了. git clone --depth 1 git://github.com/TI-OpenLink/wl18xx.git  --branch ol_r8 ...

  4. 巧妙利用ToArray()函数移除集合中的元素

    当我们对集合foreach遍历时,不能直接移除遍历的集合的元素,解决的方法有很多种,见我之前的随笔: http://www.cnblogs.com/527289276qq/p/4331000.html ...

  5. addEventListener与removeEventListener

    addEventListener:添加事件监听器 element.addEventListener(event, function, useCapture) event:事件类型,字符串,不要加&qu ...

  6. php五种常用的设计模式

    php 设计模式 1.单例模式 单例模式顾名思义,就是只有一个实例.作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的要点有三个: 一是某个类 ...

  7. ThreadLocal类及常用的线程安全类探究

    1.ThreadLocal类 ThreadLocal是Thread Local Variable的简称,意思是线程局部变量.作用是为每一个使用该变量的线程都提供一个该变量的副本,使每一个线程都能独立操 ...

  8. 关于js向jsp中传输中文乱码问题

    最近做项目遇到的js向jsp中传中文结果是乱码,不知道是否是我换了用eclipse的原因还是什么,以前用的MyEclipse反正最后解决办法如下: 1.把js文件复制到桌面: 2.打开文件并用另存为u ...

  9. useradd adduer 的区别

    区别 1). 使用useradd时,如果后面不添加任何参数选项,例如:#sudo useradd test创建出来的用户将是默认“三无”用户:一无Home Directory,二无密码,三无系统She ...

  10. hdu 1001 二叉树搜索

    Problem Description 判断两序列是否为同一二叉搜索树序列 Input 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束.接下去一行是一个序 ...