在Cocoa应用程序中,我们常常会使用到Core Foundation对象,例如CFArrayRef 或者 CFMutableDictionaryRef等等,编译器不会自动管理Core Foundation对象的生命周期,你必须根据Core Foundation的内存管理规则来手动管理。
同时,我们经常又面临着CoreFoundation对象与Object-C对象的转换,在转换中用到的关键字就是bridge,如果使用不好会造成内存泄露,或者crash,设置直接编译不通过。下面描述一下bridge的概念和用法。
(和平转移)__bridge 转换Objective-C 和 Core Foundation 指针,不移交持有权.
(穿上铠甲)__bridge_retained 或 CFBridgingRetain 转换 Objective-C 指针到Core Foundation 指针并移交持有权。你要负责调用 CFRelease 或一个相关的函数来释放对象.
(卸下防备)__bridge_transfer 或 CFBridgingRelease 传递一个非Objective-C 指针到 Objective-C 指针并移交持有权给ARC。ARC负责释放对象。
第二种和第三种转交了所有权,即时用的的方式来管理计数引用,比如一个Core-Foundation对象用__bridge-transfer转换成了一个OC对象,那么就不需要再调用CFRelease来释放了,因为系统在检测到bridge-transfer关键字的时候可能就已经调用相应方法释放一次,再将所有权转给了OC,那么OC的ARC就可以接管一切了。
下面看几个例子:
-
Core-Foundation与OC转换没有使用__bridge参数,编译器直接报错。
-
将OC对象转成Core-Foundation,没有使用__bridge_retain转换持有权,结果超出OC的生命周期后运行时crash。
应该改为 p=(__bridge_retain void*)obj;
用__bridge_transfer 将Core-Foundation转成OC并转交控制权后,仍然一意孤行用老方法做CFRelease, 导致两次释放,最终crash。