自 Xcode4.2 开始导入ARC机制后,为了支持对象间的转型,Apple又增加了许多转型用的关键字。这一讲我们就来了解其用法,以及产生的理由。
引子
我们先来看一下ARC无效的时候,我们写id类型转void*类型的写法:
1 2 |
id obj = [[NSObject alloc] init]; void *p = obj; |
反过来,当把void*对象变回id类型时,只是简单地如下来写,
1 2 |
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*类型的相互转换。看下面的例子。
1 2 3 4 5 |
id obj = [[NSObject alloc] init]; void *p = (__bridge void *)obj; id o = (__bridge id)p; |
将Objective-C的对象类型用 __bridge 转换为 void* 类型和使用 __unsafe_unretained 关键字修饰的变量是一样的。被代入对象的所有者需要明确对象生命周期的管理,不要出现异常访问的问题。
除过 __bridge 以外,还有两个 __bridge 相关的类型转换关键字:
- __bridge_retained
- __bridge_transfer
接下来,我们将看看这两个关键字的区别。
__bridge_retained
先来看使用 __bridge_retained 关键字的例子程序:
1 2 3 |
id obj = [[NSObject alloc] init]; void *p = (__bridge_retained void *)obj; |
从名字上我们应该能理解其意义:类型被转换时,其对象的所有权也将被变换后变量所持有。如果不是ARC代码,类似下面的实现:
1 2 3 4 |
id obj = [[NSObject alloc] init]; void *p = obj; [(id)p retain]; |
可以用一个实际的例子验证,对象所有权是否被持有。
1 2 3 4 5 6 7 8 |
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无效的时候,我们可能需要写下面的代码。
1 2 3 4 |
// p 变量原先持有对象的所有权 id obj = (id)p; [obj retain]; [(id)p release]; |
那么ARC有效后,我们可以用下面的代码来替换:
1 2 |
// 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时,我们用下面的代码:
1 2 |
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 后的代码如下:
1 2 |
NSString *string = [NSString stringWithFormat:...]; CFStringRef cfString = (__bridge CFStringRef)string; |
只是单纯地执行了类型转换,没有进行所有权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。
1 2 3 4 |
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对象类型的相互转换,提供了下面的函数。
1 2 3 4 5 6 7 |
CFTypeRef CFBridgingRetain(id X) { return (__bridge_retained CFTypeRef)X; } id CFBridgingRelease(CFTypeRef X) { return (__bridge_transfer id)X; } |
所以,可以用 CFBridgingRetain 替代 __bridge_retained 关键字:
1 2 3 4 |
NSString *string = [NSString stringWithFormat:...]; CFStringRef cfString = CFBridgingRetain(string); ... CFRelease(cfString); // 由于Core Foundation不在ARC管理范围内,所以需要主动release。 |
所有权被转移的同时,被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会经常用到 __bridge_transfer 关键字。
1 2 3 4 |
CFStringRef cfString = CFStringCreate...(); NSString *string = (__bridge_transfer NSString *)cfString; // CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权,所以不需要调用 release |
同样,我们可以使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字。
1 2 |
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 处理。
from http://www.yifeiyang.net/development-of-the-iphone-simply-6/
相关推荐
《深入浅出iPhone开发》是一本专为iPhone应用程序开发初学者编写的指南,旨在通过实际应用案例,系统地介绍iOS开发的各项技术。本书的核心目标是让读者能够从零基础逐步掌握开发iPhone应用所需的知识和技能。 在iOS...
深入浅出iPhone/iPad开发(第2版)是HeadFirst系列图书的一本最新力作。全书通过轻松的图文方式,由浅入深地向读者介绍SDK和Object-C的基础知识,以及如何构建并测试简单的应用模型,并提供如何利用iPhone/iPad的相机...
知名的Head First系列丛书之一,风格与其他Head First系列一脉相承,一定能让读者轻松学会iPhone开发,《深入浅出iPhone开发》是针对iPhone开发的初学者设计的,以几个应用实例的开发为例,循序渐进地对iPhone开发的...
深入浅出iPhone/iPad开发(第2版)》是HeadFirst系列图书的一本最新力作。全书通过轻松的图文方式,由浅入深地向读者介绍SDK和Object-C的基础知识,以及如何构建并测试简单的应用模型,并提供如何利用iPhone/iPad的...
《深入浅出iPhone/iPad开发(第2版)》是HeadFirst系列图书的一本最新力作。全书通过轻松的图文方式,由浅入深地向读者介绍SDK和Object-C的基础知识,以及如何构建并测试简单的应用模型,并提供如何利用iPhone/iPad...
《深入浅出iPhone开发(中文版)》是针对iPhone应用开发的一本专业书籍,由丹皮洛内原著,鲁成东翻译。这本书旨在为读者提供一个全面、深入且易懂的iPhone开发学习路径,帮助开发者从零基础快速掌握iPhone应用程序的...
《软件创富密码:iPhone应用程序开发攻略之深入浅出Objective-C2.0(适用于ios4)》系统地介绍了关于使用Objective-C2.0开发iPhone应用程序的基础知识,涵盖各种开发工具的操作技巧、框架(Framework)内部的工作原理...
《软件创富密码:iPhone应用程序开发攻略之深入浅出Objective-C2.0(适用于ios4)》系统地介绍了关于使用Objective-C2.0开发iPhone应用程序的基础知识,涵盖各种开发工具的操作技巧、框架(Framework)内部的工作原理...
《深入浅出iPhone/iPad开发(第2版)》是一本专为想要学习或已经从事iOS应用开发的人员量身打造的专业书籍。该书全面覆盖了iPhone和iPad应用开发的知识点,旨在帮助读者掌握Apple的iOS开发平台,利用Swift语言进行...
《深入浅出iPhone开发》是一本专门为iPhone开发初学者准备的教材,它的目的是通过实例教学的方式,让开发者逐步掌握iPhone应用开发的各个方面。这本书强调的是实践和实例,通过具体的项目开发案例,让学习者能够更加...
《深入浅出iPhone开发》,本书是针对iPhone开发的初学者设计的,以几个应用实例的开发为例,循序渐进地对iPhone开发的各个方面进行了讲解。
《iPhone应用程序开发攻略之深入浅出Objective-C 2.0》是王志刚撰写的一本专为iOS开发者设计的教程,旨在帮助读者掌握Objective-C 2.0编程语言,从而能够开发高质量的iPhone应用程序。Objective-C是苹果公司开发的...
《深入浅出iPhone开发》是一本专为iPhone应用程序开发初学者编写的指南,旨在通过实践案例引领读者逐步掌握iOS开发的核心技术。这本书涵盖了从环境搭建到应用发布的全过程,旨在帮助读者从零基础到能够独立创建功能...
《深入浅出iPhone Pad开发》这本书是为想要开发iPhone和iPad应用的开发者提供的实用指南。从标题来看,它主要面向的是希望深入了解苹果iOS平台移动应用开发的读者。对于任何对iOS开发感兴趣的开发者来说,这本书都...
《深入浅出iPhone开发彩色版》是一本专为初学者设计的iOS开发指南,它旨在通过最新的开发工具和直观的教学方式,帮助读者快速掌握iPhone应用的开发技能。这本书以丰富的色彩和直观的示例,使得枯燥的技术知识变得...
《深入浅出iPhone编程》是Head First系列中的一本专为初学者设计的iOS开发教程,专注于iPhone应用的开发。本书的第11章在前10章的基础上,继续深入探讨iOS开发的关键技术和实践,旨在帮助读者理解并掌握iPhone应用...
《深入浅出设计模式》是设计模式领域的一本经典著作,其第一章就详细介绍了策略模式。策略模式的核心思想是定义一系列算法,并将每一个算法封装起来,使它们可以相互替换。这样,算法的变化就不会影响到使用算法的...