Core Foundation
是一组 C 语言接口,Foundation
用 Objective-C 封装了 Core Foundation 的 C 组件,并实现了额外了组件供开发人员使用。而 Core Foundation 也有一些 Foundation 没能彻底封装的功能,这些功能是 Core Foundation 特有的。Core Foundation 有 Foundation 没有的功能,比如 CFDictionary 的 Key 元素无需实现 NSCoping 协议、CFArray 可以不进行对象引用计数等、CFRunloop 提供了比 NSRunloop 更加细致化的 Api、利用 CFStringTransform 将中文转为拼音。反过来,Foundation 也有 Core Foundation 无法胜任的工作,最大的来说就是自动引用计数功能,还有比如 NSBundle 在 Core Foundation 中也没有。
先说下出现这两个框架的历史原因,当年乔布斯被自己创办的公司驱逐后,成立了
NeXT Computer
公司,拥有NeXTSTEP
操作系统,后来乔布斯回到苹果后,就出现了一个问题。如何让旧的系统(Mac OS 9)和 NeXTSTEP 合成为一个新系统,这就需要一个更为底层的核心库可以供 Mac Toolbox 和 OPENSTEP 双方调用。Core Foundation 就这么诞生了。其中 Foundation 对象是 NS 开头的原因也是由于 NeXTSTEP 系统。
Core Foundation 中的对象也是使用引用计数的方式管理内存,对应的方式为 CFRetain
、CFRelease
。但是不同的是,ARC 可以管理 NS 对象指针,但是无法管理 CF 对象指针,所以即使在 ARC 中,CF 对象也需要手动管理引用计数。当然因为 CF 和 Foundation 之间的友好关系,它们之间的管理权也是可以移交的,这种管理权移交的技术叫做 Toll-Free Bridging
。
每一个能够 bridge 的 ObjC 类,都是一个类簇(class cluster)。类簇是一个公开的抽象类,但其核心功能的是在不同的私有子类中实现的,公开类只暴露一致的接口和实现一些辅助的创建方法。而与该 ObjC 类相对应的 Core Foundation 类的内存结构,正好与类簇的其中一个私有子类相同。举个例子,NSString 是一个类簇,一个公开的抽象类,但每次创建一个 NSString 的实例时,实际上我们会获得其中一个私有子类的实例。
先提前说明一下,可以在 XCode 中通过调整
Build Settings -> Objective-C Automatic Reference Counting
参数来控制内存管理是选用 ARC 还是 MRC,YES 为 ARC,反之则为 MRC。
在 MRC 环境下,CF 对象与 NS 对象可以相互强制转换,内存所有权归各自所有,进行手动控制
// 以下代码如果在ARC环境下会自动提示编译错误,并给出改正提示
- (void)testBridgeInMRC{
// OC转CF
NSString *originOCStr = [NSString stringWithFormat:@"OC"];
CFStringRef cfStr = (CFStringRef)originOCStr;
NSLog(@"%@ %@", originOCStr, cfStr);
[originOCStr release];
CFRelease(cfStr);
// CF转OC
CFStringRef originCFStr = CFStringCreateWithCString(CFAllocatorGetDefault(), "CF", kCFStringEncodingUTF8);
NSString *ocStr = (NSString *)originCFStr;
NSLog(@"%@ %@", ocStr, originCFStr);
[ocStr release];
CFRelease(originCFStr);
}
在 ARC,CF 与 OC 之间的转化方式有三种。
__bridge
// 当originOCStr被ARC释放后,cfStr指向的对象也是被释放了,如果继续使用cfStr则会引起程序崩溃。
NSString *originOCStr = [[NSString alloc]initWithFormat:@"OC"];
CFStringRef cfStr = (__bridge CFStringRef) originOCStr;
CFStringRef originCFStr = CFStringCreateWithCString(NULL, "CF", kCFStringEncodingUTF8);
NSString *ocStr = (__bridge NSString *)originCFStr;
// 需要人工CFRelease,否则,OC对象的指针释放后,对象引用计数仍为1,不会被销毁
CFRelease(originCFStr);
__bridge_retained
// OC->CF __bridge_retained
NSString *originOCStr = [[NSString alloc]initWithFormat:@"OC"];
CFStringRef cfStr = (__bridge_retained CFStringRef) originOCStr;
//这时候,即使开启ARC,也需要手动执行CFRelease,因为此时对象管理已经交给CF管理了
CFRelease(cfStr);
__bridge_transfer
// CF->OC __bridge_transfer
CFStringRef originCFStr = CFStringCreateWithCString(NULL, "CF", kCFStringEncodingUTF8);
NSString *ocStr = (__bridge_transfer NSString *)originCFStr;
并不是所有的 CF 对象都支持 Toll-Free Bridging
,以下是支持的结构类型表。
CF-NS.png