• 浅解ARC中的 __bridge、__bridge_retained和__bridge_transfer


    文章来源:http://www.outflush.com/2015/03/introduction-of-arc-bridge-type-transfer/

    在对 bridge 相关的修饰符解说前。首先了解下面内容

    • Core Foundation 是一组C语言接口。它与Foundation为相同功能提供接口。仅仅是Foundation框架提供的是Objective-C接口。
    • Core Foundation中的对象也存在引用计数的概念,相似于Foundation的retain/release,其相应的接口是CFRetain/CFRelease
    • 这两个框架的对象之间能够相互转换,这样的转换被称之为Toll-Free bridge
    • 当使用ARC时,Core Foundation中的对象不被ARC所管理。所以Core Foundation和Foundation中的对象在相互转换的过程中会涉及到对象全部权的转换。这里便用到了bridge修饰符。

    普通对象与C语言指针之间的转换

    void *p = NULL;
    {
    id obj = [[NSObject alloc] init];
    p = (__bridge void *)obj;
    }
    NSLog(@"Hello");
    
    // 这里会出现错误
    NSLog(@"%@", [(__bridge id)p class]);

    上面代码中的obj被ARC管理,p是一个C语言指针。不在ARC的管理范围中。当程序运行到obj的作用域之外。ARC便将obj给release掉,这时p指针成为NULL。所以在使用__bridge的时候必须清楚对象的生命周期否则便会出现相似上面的错误。

    这时便应该使用__bridge_retain关键字来进行转换

    p = (__bridge_retain void *)obj;
    
    // 上面这段代码在非ARC的环境下能够表示为
    p = obj;
    [(id)p retain];

    所以当obj被ARC release后,p指针仍然指向一个有效的对象。

    __bridge_transfer则是用于将一个通过__bridge_retain转换得到的C语言指针又一次转换为被ARC管理的普通对象。

    id obj = (__bridge_transfer id)p;
    
    // 用非ARC来表示就是
    id obj = p;
    [obj retain];
    [(id)p release];

    能够看出,__bridge_transfer将p指向的对象的全部权转移到了ARC管理的obj上。

    当在ARC环境中声明 id obj 时。默认是 strong 修饰符修饰的,所以ARC会自己主动对obj进行retain处理。所以说__bridge_transfer仅仅做了release处理。

    Core Foundation与Foundation普通对象之间的转换

    从上面已经知道Core Foundation中的对象也存在引用计数的概念。当在非ARC环境下,Core Foundation对象和Foundation对象能够通过标准的C语言类型转换来进行转换(Toll-Free bridge)。而当引入ARC后则须要bridge来进行转换,由于你须要明白的告诉编译器怎样处理对象的全部权。

    比如:

    NSString *str = [NSString stringWithFormat…];
    CFStringRef cfStr = (__bridge CFStringRef)str;
    ...
    CFRelease(cfStr);

    这里str对象被ARC所管理,而cfStr并不在ARC的管理中,由于__bridge仅仅是单纯的进行了类型转换,所以当str被ARC release后,cfStr便成为了NULL。

    而当上面这段代码使用__bridge_retain进行转换后。cfStr便拥有了str对象的全部权,这时假设str被ARC release,cfStr仍然有效。

    然而又由于Core Foundation中的对象也存在引用计数概念。所以须要使用CFRelease()手动的对cfStr进行release操作。

    代码例如以下:

    NSString *str = [NSString stringWithFormat…];
    CFStringRef cfStr = (__bridge_retain CFStringRef)str;
    ...
    CFRelease(cfStr);

    至于__bridge_transfer,从上文能够得知其用于将对象的全部权转移,所以CF(Core Foundation简写)对象在使用__bridge_transfer转换为Foundation对象后被释放。

    CFStringRef cfStr = CFStringCreate…();
    NSString *str = (__bridge_transfer NSString *)cfStr;
    
    // 在非ARC环境下,上面这句等同于
    NSString *str = cfStr;
    CFRelease(cfStr);

    实际上,在Core Foundation内部存在两个用于CF对象和Foundation对象转换的函数

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

    使用这两个函数相同能够进行两者对象之间的类型转换。

    总结

    • bridge 用于被ARC管理的对象和不被ARC管理的对象之间的转换
    • __bridge 仅仅负责单纯的类型转换,须要格外注意对象的生存周期。

    • __bridge_retain 将被ARC管理的对象转换为不被ARC管理的对象的同一时候,将ARC管理的对象retain。使其部分成为不被ARC管理的对象(描写叙述非常不当,自行多揣摩)。
    • __bridge_transfer 将不被ARC管理的对象转换为被ARC管理的对象的同一时候,将不被ARC管理的对象release。

  • 相关阅读:
    Android游戏开发实践(1)之NDK与JNI开发02
    SDK接入(1)之Android Facebook SDK接入
    Markdown学习
    SDK接入(3)之iOS内支付(InApp Purchase)接入
    将列【1,2,3】转换为【类别1,类别2,类别3】
    SQL Server 获取日期
    SQL Server 2000 Split方法
    java连接SqlServer2012
    前辈的js学习方法
    js学习笔记
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5136368.html
Copyright © 2020-2023  润新知