C 指针和OC 对象之间的转换方法

2020-01-06 18:40:43丽君

Core Foundation 框架

Core Foundation 框架 (CoreFoundation.framework) 是一组 C 语言接口, 简称 CF.

它们为 iOS 应用程序提供基本数据管理和服务功能.

如 Core Graphics、Core Text,并且我们可能需要将 CF 对象和OC 对象进行相互转化,ARC 下,编译器不会自动管理 CF 对象的内存,我们需要手动管理.

创建一个 CF 对象使用后, 需要使用 CFRelease 将其手动释放, 换句话说, Core Foundation 对象类型不在 ARC 管理范畴内.

如何将 CF 和 OC 对象有效的结合起来, 在 ARC 环境下, 提供了 桥接 的技术, 即 ARC 下 OC 对象和 Core Foundation 对象之间的桥梁.

ARC 桥接

ARC 下 C 指针与 OC 指针(对象)之间转换, 一般会用到下面的方法.


__bridge_retained <#CF type#>)<#expression#>
__bridge_transfer <#Objective-C type#>)<#expression#>
__bridge <#type#>)<#expression#>

也就是所谓的 桥接, 它是 Object-C 在 ARC 环境下开发出来的一种用作转换 C 指针跟 OC (类)指针的一种转换技术, 所以是 ARC 下的称谓, 在 MRC 下没有 桥接.

针对内存管理问题,ARC 可以管理 Objective-C 对象, 但不支持 Core Foundation 对象的管理,所以转换后要注意一个问题:谁来释放使用后的对象.

结合 ARC 和 内存管理, 下面分别介绍一下.

Core Foundation 对象必须使用 CFRetain 和 CFRelease 来进行内存管理.

当使用 Objective-C 和 Core Foundation 对象相互转换的时候,必须让编译器知道,到底由谁来负责释放对象,是否交给 ARC 处理, 只有正确的处理,才能避免内存泄漏和 double free 导致程序崩溃.

__bridge_retained <#CF type#>)<#expression#>

__bridge_retained 等同于 CFBridgingRetain() .

将 Objective-C 对象转换为 Core Foundation 对象,把对象所有权桥接给 Core Foundation 对象,同时剥夺 ARC 的管理权,后续需要开发者使用 CFRelease 或者相关方法手动来释放 CF 对象.

示例:


void *cPointer;
NSObject *objc = [[NSObject alloc] init];
//将 OC 对象转换为 C 指针
cPointer = (__bridge_retained void*)objc;
//use cPointer ...
//需要释放资源
CFRelease(cPointer);

在 ARC 下, CFBridgingRetain 实现如下:


NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) {
 return (__bridge_retained CFTypeRef)X;
}

关于 CFTypeRef, 如下:


typedef const CF_BRIDGED_TYPE(id) void * CFTypeRef;

所以 CFBridgingRetain 返回值是 const void * 类型的.

上面的示例可以改写为:


const void *cPointer;
const NSObject *objc = [[NSObject alloc] init];
cPointer = CFBridgingRetain(objc);
 
//use cPointer ...
 
CFRelease(cPointer);