Toll-Free Bridging

来源:互联网 发布:淘宝内裤真人秀在哪看 编辑:程序博客网 时间:2024/05/18 22:54

原文链接:http://gracelancy.com/blog/2014/04/21/toll-free-bridging/

Toll-Free Bridging

有一些数据类型是能够在 Core Foundation Framework 和 Foundation Framework 之间交换使用的。这意味着,对于同一个数据类型,你既可以将其作为参数传入 Core Foundation 函数,也可以将其作为接收者对其发送 Objective-C 消息(即调用ObjC类方法)。这种在 Core Foundation 和 Foundation 之间交换使用数据类型的技术就叫 Toll-Free Bridging.

举例说明,NSString和CFStringRef即是一对可以相互转换的数据类型:

//ARC 环境下//Bridging from ObjC to CFNSString* hello = @"world";CFStringRef world = (__bridge CFStringRef)(hello);//Bridging from CF to ObjCCFStringRef hello = CFStringCreateWithCString(kCFAllocatorDefault, "hello", kCFStringEncodingUTF8);NSString* world = (__bridge NSString *)(hello);CFRelease(hello);

MRC 下的 Toll-Free Bridging 因为不涉及内存管理的转移,可以直接相互 bridge 而不必使用类似__bridge修饰字,我们之后再讨论这个问题。

Toll-Free Bridging 实现

  • 每一个能够 bridge 的 ObjC 类,都是一个类簇(class cluster)。类簇是一个公开的抽象类,但其核心功能的是在不同的私有子类中实现的,公开类只暴露一致的接口和实现一些辅助的创建方法。而与该 ObjC 类相对应的 Core Foundation 类的内存结构,正好与类簇的其中一个私有子类相同。
    举个例子,NSString是一个类簇,一个公开的抽象类,但每次创建一个NSString的实例时,实际上我们会获得其中一个私有子类的实例。而NSString的其中一个私有子类实现既为NSCFString,其内存的结构与CFString是相同的,CFString的isa指针就指向NSCFString类,即,CFString对象就是一个NSCFString类的实例。
    所以,当NSString的实现刚好是NSCFString的时候,他们两者之间的转换是相当容易而直接的,他们就是同一个类的实例。

  • 当NSString的实现不是NSCFString的时候(比如我们自己 subclass 了NSString),我们调用 CF 函数,就需要先检查对象的具体实现。如果发现其不是NSCFString,我们不会调用 CF 函数的实现来获得结果,而是通过给对象发送与函数功能相对应的 ObjC 消息(调用相对应的NSString的接口)来获得其结果。
    例如CFStringGetLength函数,当收到一个作为参数传递进来的对象时,会先确认该对象到底是不是NSCFString实现。如果是的话,就会直接调用CFStringGetLength函数的实现来获得字符串的长度;如果不是的话,会给对象发送length消息(调用NSString的- (NSUInteger)length接口),来得到字符串的长度。
    通过这样的技术,即使是我们自己子类了一个NSString,也可以和CFStringRef相互 Bridge。

  • 其他支持 Toll-Free Bridging 的数据类型原理也同NSString一样,比如NSNumber的NSCFNumber和CFNumber。

ARC 下的 Toll-Free Bridging

如之前提到的,MRC 下的 Toll-Free Bridging 因为不涉及内存管理的转移,相互之间可以直接交换使用:

// bridgeNSString *nsStr = (NSString *)cfStr;CFStringRef cfStr = (CFStringRef)nsStr;// 调用函数或者方法NSUInteger length = [(NSString *)cfStr length];NSUInteger length = CFStringGetLength((CFStringRef)nsStr);// releaseCFRelease((CFStringRef)nsStr);[(NSString *)cfStr release];

而在 ARC 下,事情就会变得复杂一些,因为 ARC 能够管理 Objective-C 对象的内存,却不能管理 CF 对象,CF 对象依然需要我们手动管理内存。在 CF 和 ObjC 之间 bridge 对象的时候,问题就出现了,编译器不知道该如何处理这个同时有 ObjC 指针和 CFTypeRef 指向的对象。

这时候,我们需要使用__bridge, __bridge_retained, __bridge_transfer 修饰符来告诉编译器该如何去做。

__bridge

CF->ObjC : 需手动释放CF的内存(CFRelease)

ObjC->CF:不需手动释放CF,但是ObjC销毁了,CF调用会crash

__bridge_retained

ObjC->CF:对ObjC做retain操作,ObjC销毁,CF仍然可以调用,需要手动释放CF

__bridge_transfer

CF->ObjC:转意对象所有权,无需手动释放CF

0 0
原创粉丝点击