zoukankan      html  css  js  c++  java
  • Core Foundation 框架

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

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

    • 程序包

    • 字符串管理

    • 日期和时间管理

    • 原始数据块管理

    • 偏好管理

    • 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*类型的写法:

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

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

    1. id obj = p;
    2. [obj release];

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

    1. error:implicit conversion of an Objective-C pointer
    2. to void*’is disallowed with ARC
    3. void*p = obj;
    4. ^
    5.  
    6. error:implicit conversion of a non-Objective-C pointer
    7. type void*’ to idis disallowed with ARC
    8. id o = p;
    9. ^

    __bridge

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

    1. id obj =[[NSObject alloc] init];
    2.  
    3. void*p =(__bridge void*)obj;
    4.  
    5. id o =(__bridge id)p;

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

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

    • __bridge_retained
    • __bridge_transfer

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

    __bridge_retained

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

    1. id obj =[[NSObject alloc] init];
    2.  
    3. void*p =(__bridge_retained void*)obj;

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

    1. id obj =[[NSObject alloc] init];
    2.  
    3. void*p = obj;
    4. [(id)p retain];

    可以用一个实际的例子验证,对象所有权是否被持有。

    1. void*p =0;
    2.  
    3. {
    4. id obj =[[NSObject alloc] init];
    5. p =(__bridge_retained void*)obj;
    6. }
    7.  
    8. NSLog(@"class=%@",[(__bridge id)p class]);

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

    __bridge_transfer

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

    如果ARC无效的时候,我们可能需要写下面的代码。

    1. // p 变量原先持有对象的所有权
    2. id obj =(id)p;
    3. [obj retain];
    4. [(id)p release];

    那么ARC有效后,我们可以用下面的代码来替换:

    1. // p 变量原先持有对象的所有权
    2. 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时,我们用下面的代码:

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

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

    但是在ARC有效的情况下,将出现类似下面的编译错误:

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

    错误中已经提示了我们需要怎样做:用 __bridge 或者 __bridge_retained 来转型,其差别就是变更对象的所有权。

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

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

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

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

    1. NSString*string=[NSString stringWithFormat:...];
    2. CFStringRef cfString =(__bridge_retained CFStringRef)string;
    3. ...
    4. CFRelease(cfString);// 由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release

    使用 __bridge_retained 可以通过转换目标处(cfString)的 retain 处理,来使所有权转移。即使 string 变量被释放,cfString 还是可以使用具体的对象。只是有一点,由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。

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

    1. CFTypeRefCFBridgingRetain(id X){
    2. return(__bridge_retained CFTypeRef)X;
    3. }
    4.  
    5. id CFBridgingRelease(CFTypeRef X){
    6. return(__bridge_transfer id)X;
    7. }

    所以,可以用 CFBridgingRetain 替代 __bridge_retained 关键字:

    1. NSString*string=[NSString stringWithFormat:...];
    2. CFStringRef cfString =CFBridgingRetain(string);
    3. ...
    4. CFRelease(cfString);// 由于Core Foundation不在ARC管理范围内,所以需要主动release。
    __bridge_transfer

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

    1. CFStringRef cfString =CFStringCreate...();
    2. NSString*string=(__bridge_transfer NSString*)cfString;
    3.  
    4. // CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权,所以不需要调用 release

    同样,我们可以使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字。

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

    总结

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

    • 明确被转换类型是否是 ARC 管理的对象
      • Core Foundation 对象类型不在 ARC 管理范畴内
      • Cocoa Framework::Foundation 对象类型(即一般使用到的Objectie-C对象类型)在 ARC 的管理范畴内
    • 如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁
    • 各种对象的生命周期是怎样的

    1. 声明 id obj 的时候,其实是缺省的申明了一个 __strong 修饰的变量,所以编译器自动地加入了 retain 的处理,所以说 __bridge_transfer 关键字只为我们做了 release 处理。

  • 相关阅读:
    Bootstrap3入门
    Pi
    比Redis更快:Berkeley DB面面观
    搞定KMP匹配算法
    elasticsearch文档-analysis
    21本计算机数学相关的免费电子书
    [Android开发常见问题-12] Android开发中debug.keystore如何使用。
    (Java实现) 组合的输出
    (Java实现) 自然数的拆分
    (Java实现) 自然数的拆分
  • 原文地址:https://www.cnblogs.com/BinShao/p/3561338.html
Copyright © 2011-2022 走看看