id 和 void * 类型的相互转换
__bridge
通过 __bridge
桥接,id 和 void * 就能够相互转换。__bridge 为直接转换,不会对引用计数做特殊处理。
__bridge
转换其的安全性与赋值给 __unsafe_unretained 修饰符相近,甚至会更低。如果管理不注意赋值对象的所有者,就会因野指针而导致程序崩溃。
__bridge_retained
__bridge_retained 转换可以使要转换赋值的变量也持有所赋值的对象。
等价于 MRC 的如下代码:
1 | id obj = [[NSObject alloc] init]; |
看下面代码:
1 | void *p = 0; |
在大括号外打印 p 的 class,结果为 NSObject,因此 obj 在大括号结束后没有被释放,p 持有了 obj。
__bridge_transfer
__bridge_transfer 提供与 __bridge_retained 相反的动作,被转换的变量所持有的对象在该变量被赋值给转换目标变量后随之释放。
1 | id obj = (__bridge_transfer id)p; |
等价于 MRC 的:
1 | id obj = (id)p; |
用 Bridge 来管理 Objective-C 对象的内存
__bridge_retained
转换与 retain 类似,__bridge_transfer
转换与 release 类似。使用这两种转换,在不使用 id 类型或对象型变量时,也可以生成、持有以及释放对象。
例如可以使用 Bridge 来对 Objective-C 对象进行内存管理:
1 | // 创建并持有对象 |
只是这种写法不会有人这样写。
Objective-C 对象和 Core Foundation 对象之间的转换
Objective-C 对象和 Core Foundation 对象之间的区别很小,不同之处只在于是由哪个框架生成的(Foundation 和 Core Foundation)。Foundation 框架生成并持有的对象可以用 Core Foundation 框架 API 释放,反之亦可。
Objective-C 对象和 Core Foundation 对象之间的转换不需要消耗额外的 CPU 资源,因此成为免费桥(Toll-Free Bridge)。
也可以调用内置函数来进行 Objective-C 对象和 Core Foundation 对象之间的转换。
1 | CFTypeRef CFBridgingRetain(id X) { |
使用函数的效果跟直接使用关键字 __bridge_retained 和 __bridge_transfer 的效果是一样的。
避免出现野指针
看下面例子:
1 | CFMutableArrayRef cfObject = NULL; |
以上代码在运行时会崩溃,因为 cfObject 在大括号内被赋值,使用 __bridge 关键字时,cfObject 是不持有 obj 的,当出大括号后,obj 被释放,cfObject 也就成野指针的,导致崩溃。
这时需要改为 __bridge_retained 或 CFBridingRetain。
1 | CFMutableArrayRef cfObject = NULL; |