理解__bridge,__bridge_transfer和__bridge_retained

原文:https://blog.csdn.net/junjun150013652/article/details/53506504

=================以下未经说明,都是在ARC环境下==============

在Cocoa应用程序中,我们常常会使用到Core Foundation-style objects,例如CFArrayRef 或者 CFMutableDictionaryRef等等

编译器不会自动管理Core Foundation-style objects的生命周期,你必须根据Core Foundation的内存管理规则来调用[CFRetain](https://developer.apple.com/reference/corefoundation/1521269-cfretain)[CFRelease](https://developer.apple.com/reference/corefoundation/1521153-cfrelease)(或者相应的变体)

如果你在Objective-C 和 Core Foundation-style 对象之间进行转换,你必须通过以下宏来告诉编译器对象的持有者

  • __bridge 转换Objective-C 和 Core Foundation 指针,不移交持有权.

  • __bridge_retainedCFBridgingRetain 转换 Objective-C 指针到Core Foundation 指针并移交持有权.

    你要负责调用 CFRelease 或一个相关的函数来释放对象.

  • __bridge_transferCFBridgingRelease 传递一个非Objective-C 指针到 Objective-C 指针并移交持有权给ARC.

    ARC负责释放对象.

=================以上是苹果文档的说明,以下通过例子来讲解 =================

对象和c语言指针互相转换时,如下:

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

编译器会提示插入(__bridge void *) 强制转换,然而__bridge并不是安全的,管理时不注意对象的所有者,就会因为悬垂指针而导致程序崩溃。例如下面这段代码

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

因为__bridge只是简单的进行了指针转换,并没有移交持有权,作用域外obj已经释放掉了,p就相当于指向了一块已经释放的内存,因此作用域外访问p就会崩溃。

我们将上面的__bridge修改为__bridge_retained就能解决问题。相当于在作用域内对p执行了retain操作。obj的引用计数为2,作用域结束时obj释放,引用计数变为1,p仍然持有对象,使用完以后记得要调用CFRelease(p)释放p,ARC是不会负责的哦。

__bridge_transfer正好和__bridge_retained相反,是在CF对象转OC对象时,被转换的变量所持有的对象在该变量被赋值给转换目标变量后随之释放。

下面通过例子分析__bridge_transfer

    CFMutableArrayRef cfObject = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);    printf("retain count = %ld\n",CFGetRetainCount(cfObject));        id obj = CFBridgingRelease(cfObject);    printf("retain count after the cast = %ld\n",CFGetRetainCount(cfObject));

打印信息:

retain count = 1

retain count after the cast = 1

cast的时候,相当于 cfObject的持有权转交给了ARC,你不用负责obj的释放了。

你可能感兴趣的:(理解__bridge,__bridge_transfer和__bridge_retained)