IOS学习之 CoreFoundation框架

转载自 http://blog.csdn.net/weiwangchao_/article/details/7744972html


官方文档: ios

https://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CoreFoundation_Collection/index.html#//apple_ref/doc/uid/TP40003849数组

https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFDesignConcepts/CFDesignConcepts.html#//apple_ref/doc/uid/10000122-SW1app

Core Foundation框架 (CoreFoundation.framework) 是一组C语言接口,它们为iOS应用程序提供基本数据管理和服务功能。下面列举该框架支持进行管理的数据以及可提供的服务:

  • 群体数据类型 (数组、集合等)框架

  • 程序包iphone

  • 字符串管理ide

  • 日期和时间管理函数

  • 原始数据块管理oop

  • 偏好管理学习

  • URL及数据流操做

  • 线程和RunLoop

  • 端口和soket通信

Core Foundation框架和Foundation框架紧密相关,它们为相同功能提供接口,但Foundation框架提供Objective-C接口。若是您将Foundation对象和Core Foundation类型掺杂使用,则可利用两个框架之间的 “toll-free bridging”。所谓的Toll-free bridging是说您能够在某个框架的方法或函数同时使用Core Foundatio和Foundation 框架中的某些类型。不少数据类型支持这一特性,其中包括群体和字符串数据类型。每一个框架的类和类型描述都会对某个对象是否为 toll-free bridged,应和什么对象桥接进行说明。

如需进一步信息,请阅读Core Foundation 框架参考

自 Xcode4.2 开始导入ARC机制后,为了支持对象间的转型,Apple又增长了许多转型用的关键字。这一讲咱们就来了解其用法,以及产生的理由。

引子

咱们先来看一下ARC无效的时候,咱们写id类型转void*类型的写法:

id obj = [[NSObject alloc] init];void *p = obj;

反过来,当把void*对象变回id类型时,只是简单地以下来写,

id obj = p;[obj release];

可是上面的代码在ARC有效时,就有了下面的错误:

    error: implicit conversion of an Objective-C pointer        to ’void *’ is disallowed with ARC        void *p = obj;                  ^     error: implicit conversion of a non-Objective-C pointer        type ’void *’ to ’id’ is disallowed with ARC        id o = p;                ^

__bridge

为了解决这一问题,咱们使用 __bridge 关键字来实现id类型与void*类型的相互转换。看下面的例子。

id obj = [[NSObject alloc] init]; void *p = (__bridge void *)obj; id o = (__bridge id)p;

将Objective-C的对象类型用 __bridge 转换为 void* 类型和使用 __unsafe_unretained 关键字修饰的变量是同样的。被代入对象的全部者须要明确对象生命周期的管理,不要出现异常访问的问题。

除过 __bridge 之外,还有两个 __bridge 相关的类型转换关键字:

  • __bridge_retained

  • __bridge_transfer

接下来,咱们将看看这两个关键字的区别。

__bridge_retained

先来看使用 __bridge_retained 关键字的例子程序:

id obj = [[NSObject alloc] init]; void *p = (__bridge_retained void *)obj;

从名字上咱们应该能理解其意义:类型被转换时,其对象的全部权也将被变换后变量所持有。若是不是ARC代码,相似下面的实现:

id obj = [[NSObject alloc] init]; void *p = obj;[(id)p retain];

能够用一个实际的例子验证,对象全部权是否被持有。

void *p = 0; {    id obj = [[NSObject alloc] init];    p = (__bridge_retained void *)obj;} NSLog(@"class=%@", [(__bridge id)p class]);

出了大括号的范围后,p 仍然指向一个有效的实体。说明他拥有该对象的全部权,该对象没有由于出其定义范围而被销毁。

__bridge_transfer

相反,当想把原本拥有对象全部权的变量,在类型转换后,让其释放原先全部权的时候,须要使用 __bridge_transfer 关键字。文字有点绕口,咱们仍是来看一段代码吧。

若是ARC无效的时候,咱们可能须要写下面的代码。

// p 变量原先持有对象的全部权id obj = (id)p;[obj retain];[(id)p release];

那么ARC有效后,咱们能够用下面的代码来替换:

// p 变量原先持有对象的全部权id obj = (__bridge_transfer id)p;

能够看出来,__bridge_retained 是编译器替咱们作了 retain 操做,而 __bridge_transfer 是替咱们作了 release1

Toll-Free bridged

在iOS世界,主要有两种对象:Objective-C 对象和 Core Foundation 对象0。Core Foundation 对象主要是有C语言实现的 Core Foundation Framework 的对象,其中也有对象引用计数的概念,只是否是 Cocoa Framework::Foundation Framework 的 retain/release,而是自身的 CFRetain/CFRelease 接口。

这两种对象间能够互相转换和操做,不使用ARC的时候,单纯的用C缘由的类型转换,不须要消耗CPU的资源,因此叫作 Toll-Free bridged。好比 NSArray和CFArrayRef, NSString和CFStringRef,他们虽然属于不一样的 Framework,可是具备相同的对象结构,因此能够用标准C的类型转换。

好比不使用ARC时,咱们用下面的代码:

NSString *string = [NSString stringWithFormat:...];CFStringRef cfString = (CFStringRef)string;

一样,Core Foundation类型向Objective-C类型转换时,也是简单地用标准C的类型转换便可。

可是在ARC有效的状况下,将出现相似下面的编译错误:

    Cast of Objective-C pointer type ‘NSString *’ to C pointer type ‘CFStringRef’ (aka ‘const struct __CFString *’) requires a bridged cast    Use __bridge to convert directly (no change in ownership)    Use __bridge_retained to make an ARC object available as a +1 ‘CFStringRef’ (aka ‘const struct __CFString *’)

错误中已经提示了咱们须要怎样作:用 __bridge 或者 __bridge_retained 来转型,其差异就是变动对象的全部权。

正由于Objective-C是ARC管理的对象,而Core Foundation不是ARC管理的对象,因此才要特地这样转换,这与id类型向void*转换是一个概念。也就是说,当这两种类型(有ARC管理,没有ARC管理)在转换时,须要告诉编译器怎样处理对象的全部权。

上面的例子,使用 __bridge/__bridge_retained 后的代码以下:

NSString *string = [NSString stringWithFormat:...];CFStringRef cfString = (__bridge CFStringRef)string;

只是单纯地执行了类型转换,没有进行全部权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。

NSString *string = [NSString stringWithFormat:...];CFStringRef cfString = (__bridge_retained CFStringRef)string;...CFRelease(cfString); // 因为Core Foundation的对象不属于ARC的管理范畴,因此须要本身release

使用 __bridge_retained 能够经过转换目标处(cfString)的 retain 处理,来使全部权转移。即便 string 变量被释放,cfString 仍是可使用具体的对象。只是有一点,因为Core Foundation的对象不属于ARC的管理范畴,因此须要本身release。

实际上,Core Foundation 内部,为了实现Core Foundation对象类型与Objective-C对象类型的相互转换,提供了下面的函数。

CFTypeRef  CFBridgingRetain(id  X)  {    return  (__bridge_retained  CFTypeRef)X;} id  CFBridgingRelease(CFTypeRef  X)  {    return  (__bridge_transfer  id)X;}

因此,能够用 CFBridgingRetain 替代 __bridge_retained 关键字:

NSString *string = [NSString stringWithFormat:...];CFStringRef cfString = CFBridgingRetain(string);...CFRelease(cfString); // 因为Core Foundation不在ARC管理范围内,因此须要主动release。
  • __bridge_transfer


全部权被转移的同时,被转换变量将失去对象的全部权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会常常用到 __bridge_transfer 关键字。

CFStringRef cfString = CFStringCreate...();NSString *string = (__bridge_transfer NSString *)cfString; // CFRelease(cfString); 由于已经用 __bridge_transfer 转移了对象的全部权,因此不须要调用 release

一样,咱们可使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字。

CFStringRef cfString = CFStringCreate...();NSString *string = CFBridgingRelease(cfString);

总结

由上面的学习咱们了解到 ARC 中类型转换的用法,那么咱们实际使用中按照怎样的原则或者方法来区分使用呢,下面我总结了几点关键要素。

  • 明确被转换类型是不是 ARC 管理的对象

    • Core Foundation 对象类型不在 ARC 管理范畴内

    • Cocoa Foundation 对象类型(即通常使用到的Objectie-C对象类型)在 ARC 的管理范畴内

  • 若是不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁

  • 各类对象的生命周期是怎样的



__bridge

        只作类型转换,不改变对象全部权

__bridge_retained/CFBridgingRetain()

        将Objective-C对象转换为Core Foundation对象,解除ARC全部权,须要开发者使用CFRelease或者相关方法手动来释放对象。

__bridge_transfer/CFBridgingRelease

        将非Objective-C对象转换为Objective-C对象,给予ARC全部权,同时将对象的管理权交给ARC,开发者无需手动管理内存。

相关文章
相关标签/搜索