__bridge、__bridge_retained和 __bridge_transfer的用法

(1)Foundation与Core Foundation对象

Foundation创建出来的对象就是Object-C对象, Core Foundation对象主要是使用C语言编写的Core Foundation 框架中,并使用引用计数的对象。在ARC 无效是,Core Foundation框架中的retain/release分别是CFRetain/CFRelease。Core Foundation 与 Foundation 框架创建出来的对象区别很小,可以在不同的框架中使用,Foundation框架的API生成并持有的对象可以用Core Foundation框架的API释放,反过来也可以。

因为Core Foundation对象与Foundation对象没有区别,转换不需要额外的CPU资源,因此也被称为“免桥接”Toll - Free - Bridge。

(2)显示转换id 和 void*

/* MRC环境下 转换*/

id obj = [[NSObject alloc] init];

void *p = obj;

id o = p;

[o release];

/*ARC环境下 转换*/

在ARC环境下上面代码会引起编译错误,(个人猜测MRC下Foundation与Core Foundation对象都需要手动管理,而ARC环境下Foundation对象内存不需要手动管理Core Foundation对象需要,所以不能直接转需要桥接)

id obj = [[NSObject alloc] init];

void *p = (__bridge void *)obj;

id o = (__bridge id)p;

但是__bridge并不转让对象所有者,其安全性和__unsafe_unretained修饰符相近,甚至更低,如果不注意对象持有者会引起悬垂指针。桥接转换还有另外两种方式,分别是__bridge_retained和__bridge_transfer转换

__bridge_retained转换可使要转换赋值的变量也持有所赋值的对象。在MRC下其源代码是:

id obj = [[NSObject alloc] init];

void *p = obj;

[(id)p retain];

ARC环境下可以写成:

void *p = 0;

{

id obj = [[NSObject alloc] init];

p = (__bridge_retained void *)obj;

}

NSLog(@“class = %@“, [(__bridge id) p]);

obj变量作用域虽然结束了,但是由于__bridge_retained转换使p处于持有该对象的状态,因此对象不会被释放,用完需要手动释放p。

__briege_transfer转换提供与__bridge_retained相反的动作,被转换的变量所持有的对象在改变量赋值后会随之释放。

id obj = (__bridge_transfer id)p;

/*在MRC下表述为*/

id obj = (id)p

[obj retain];

[(id)p release];

(3)Foundation与Core Foundation对象转换 (终于讲到重点了)

** Foundation ——> Core Foundation

/*MRC环境下*/

CFMutableArrayRef cfobject = NULL;

{

id obj = [[NSMutableArray alloc] init];

[obj retain]

cfObject = (CFMutableArrayRef)obj;

CFRetain(cfobject); //记得持有对象

[obj release];

}

CFShow(cfObject);

CFRelease(cfObject);

/*ARC环境下*/

CFMutableArrayRef cfobject = NULL;

{

id obj = [[NSMutableArray alloc] init];//ARC下obj内存管理修饰符默认为__string,所以obj将持有对象

cfObject = (__bridge_retained  CFMutableArrayRef)obj; //cfobject已经持有对象

}

//超出作用域,obj释放,但是cfobject还持有对象,所以对象不会释放(ARC管理Foundation对象不管理Core Foundation对象内存)

CFShow(cfObject);

CFRelease(cfObject);

**Core Foundation ——> Foundation

/*MRC环境下*/

{

CFMutableArrayRef cfObject = CFArrayCreateMutable(KCFAllocatorDefault, 0, NULL);

id obj = (id)cfObject;

[obj retained];

CFRelease(cfobject);

NSLog(@“clase=%@“, obj);

[obj release];//此时对象不再拥有持有者,将被释放

}

/*ARC环境下*/

{

CFMutableArrayRef cfObject = CFArrayCreateMutable(KCFAllocatorDefault, 0, NULL);

id obj = (__bridge_transfer id)cfObject; //对象赋值完成后cfObject不在持有对象引用将被释放,但是obj默认修饰符为__strong,所以obj将持有对象

NSLog(@“clase=%@“, obj);

}

//超出作用域,obj释放,此时对象不再拥有持有者,将被释放。

个人总结下:__bridge_retained是在桥接后让Core Foundation对象变量持有对象,即让对象引用计数+1,__bridge_transfer桥接后让Core Foundation对象变量释放所持有的对象,即让对象引用计数-1。而__bridge除了桥接其他什么操作都不做。在ARC环境下,下面的操作是对等的:

cfObject = (__bridge CFMutableArrayRef)obj + CFRetain(cfObject)  与 cfObject = (__bridge_retained CFMutableArrayRef)obj

obj = (__bridge id)cfObject + CFRelease(cfObject) 与 obj = (__bridge_transfer id)cfObject

=======================================================

以上部分作者:mr_f_knight

链接:http://www.jianshu.com/p/df74a54b6b75

========================================================

原则上从oc转c使用__bridge,这样的话ARC释放oc对象的时候,c的CFRef也指向null。

从c转oc使用__bridge_transfer,将c对象的所有权转移到oc,当oc对象被ARC自动回收的时候,c的CFRef指向null。

另外,如果c转oc只使用__bridge,则oc对象不持有c对象的引用,被ARC回收的时候并不会让引用计数-1,则需要CFRelease手动释放c对象。

一般见不到__bridge_retain的用法。

例如AFNetworking中的用法:

static NSData * AFSecKeyGetData(SecKeyRef key) {

        CFDataRef data = NULL;

        __Require_noErr_Quiet(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out);

        return (__bridge_transfer NSData *)data;

_out:

        if (data) {

                CFRelease(data);

        }

        return nil;

}

如果SecItemExport发生错误,代码goto到_out: 那么就需要手动释放data指针引用的c对象。

而如果没有错误,那么把持有权转交给返回值的NSData的对象,则data的引用retain-1,接收返回值的指针变量retain+1,这样就可以通过ARC来控制释放了。

另外一个例子:

static inline NSString * AFContentTypeForPathExtension(NSString *extension) {

        NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);

        NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);

        if (!contentType) {

                return @"application/octet-stream";

        } else {

                return contentType;

        }

}

这里没有涉及到向外传递c对象的引用,那么第一步和第二步完全可以不通过__bridge_transfer,而是用CFStringRef来从第一行和第二行传递变量。

写成这样

CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);

NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType);

但这样就要通过CFRelease(UTI)释放,而使用__bridge_transfer就不用管UTI的引用计数了。

参考:http://www.jianshu.com/p/82cbacc7e07b

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容