__bridge砰苍、__bridge_retained和 __bridge_transfer的用法

(1)Foundation與Core Foundation對(duì)象

Foundation創(chuàng)建出來的對(duì)象就是Object-C對(duì)象, Core Foundation對(duì)象主要是使用C語(yǔ)言編寫的Core Foundation 框架中扯躺,并使用引用計(jì)數(shù)的對(duì)象讯柔。在ARC 無(wú)效是,Core Foundation框架中的retain/release分別是CFRetain/CFRelease臭胜。Core Foundation 與 Foundation 框架創(chuàng)建出來的對(duì)象區(qū)別很小莫其,可以在不同的框架中使用,F(xiàn)oundation框架的API生成并持有的對(duì)象可以用Core Foundation框架的API釋放耸三,反過來也可以乱陡。

因?yàn)镃ore Foundation對(duì)象與Foundation對(duì)象沒有區(qū)別,轉(zhuǎn)換不需要額外的CPU資源仪壮,因此也被稱為“免橋接”Toll - Free - Bridge憨颠。

(2)顯示轉(zhuǎn)換id 和 void*

/* MRC環(huán)境下 轉(zhuǎn)換*/

id obj = [[NSObject alloc] init];

void *p = obj;

id o = p;

[o release];

/*ARC環(huán)境下 轉(zhuǎn)換*/

在ARC環(huán)境下上面代碼會(huì)引起編譯錯(cuò)誤,(個(gè)人猜測(cè)MRC下Foundation與Core Foundation對(duì)象都需要手動(dòng)管理积锅,而ARC環(huán)境下Foundation對(duì)象內(nèi)存不需要手動(dòng)管理Core Foundation對(duì)象需要爽彤,所以不能直接轉(zhuǎn)需要橋接)

id obj = [[NSObject alloc] init];

void *p = (__bridge void *)obj;

id o = (__bridge id)p;

但是__bridge并不轉(zhuǎn)讓對(duì)象所有者,其安全性和__unsafe_unretained修飾符相近缚陷,甚至更低适篙,如果不注意對(duì)象持有者會(huì)引起懸垂指針。橋接轉(zhuǎn)換還有另外兩種方式蹬跃,分別是__bridge_retained和__bridge_transfer轉(zhuǎn)換

__bridge_retained轉(zhuǎn)換可使要轉(zhuǎn)換賦值的變量也持有所賦值的對(duì)象匙瘪。在MRC下其源代碼是:

id obj = [[NSObject alloc] init];

void *p = obj;

[(id)p retain];

ARC環(huán)境下可以寫成:

void *p = 0;

{

id obj = [[NSObject alloc] init];

p = (__bridge_retained void *)obj;

}

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

obj變量作用域雖然結(jié)束了,但是由于__bridge_retained轉(zhuǎn)換使p處于持有該對(duì)象的狀態(tài)蝶缀,因此對(duì)象不會(huì)被釋放丹喻,用完需要手動(dòng)釋放p。

__briege_transfer轉(zhuǎn)換提供與__bridge_retained相反的動(dòng)作翁都,被轉(zhuǎn)換的變量所持有的對(duì)象在改變量賦值后會(huì)隨之釋放碍论。

id obj = (__bridge_transfer id)p;

/*在MRC下表述為*/

id obj = (id)p

[obj retain];

[(id)p release];

(3)Foundation與Core Foundation對(duì)象轉(zhuǎn)換 (終于講到重點(diǎn)了)

** Foundation ——> Core Foundation

/*MRC環(huán)境下*/

CFMutableArrayRef cfobject = NULL;

{

id obj = [[NSMutableArray alloc] init];

[obj retain]

cfObject = (CFMutableArrayRef)obj;

CFRetain(cfobject); //記得持有對(duì)象

[obj release];

}

CFShow(cfObject);

CFRelease(cfObject);

/*ARC環(huán)境下*/

CFMutableArrayRef cfobject = NULL;

{

id obj = [[NSMutableArray alloc] init];//ARC下obj內(nèi)存管理修飾符默認(rèn)為__string,所以obj將持有對(duì)象

cfObject = (__bridge_retained? CFMutableArrayRef)obj;?//cfobject已經(jīng)持有對(duì)象

}

//超出作用域柄慰,obj釋放鳍悠,但是cfobject還持有對(duì)象税娜,所以對(duì)象不會(huì)釋放(ARC管理Foundation對(duì)象不管理Core Foundation對(duì)象內(nèi)存)

CFShow(cfObject);

CFRelease(cfObject);

**Core Foundation ——> Foundation

/*MRC環(huán)境下*/

{

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

id obj = (id)cfObject;

[obj retained];

CFRelease(cfobject);

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

[obj release];//此時(shí)對(duì)象不再擁有持有者,將被釋放

}

/*ARC環(huán)境下*/

{

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

id obj = (__bridge_transfer id)cfObject; //對(duì)象賦值完成后cfObject不在持有對(duì)象引用將被釋放藏研,但是obj默認(rèn)修飾符為__strong敬矩,所以obj將持有對(duì)象

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

}

//超出作用域,obj釋放蠢挡,此時(shí)對(duì)象不再擁有持有者弧岳,將被釋放。

個(gè)人總結(jié)下:__bridge_retained是在橋接后讓Core Foundation對(duì)象變量持有對(duì)象业踏,即讓對(duì)象引用計(jì)數(shù)+1禽炬,__bridge_transfer橋接后讓Core Foundation對(duì)象變量釋放所持有的對(duì)象,即讓對(duì)象引用計(jì)數(shù)-1勤家。而__bridge除了橋接其他什么操作都不做腹尖。在ARC環(huán)境下,下面的操作是對(duì)等的:

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.reibang.com/p/df74a54b6b75

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

原則上從oc轉(zhuǎn)c使用__bridge伐脖,這樣的話ARC釋放oc對(duì)象的時(shí)候热幔,c的CFRef也指向null。

從c轉(zhuǎn)oc使用__bridge_transfer讼庇,將c對(duì)象的所有權(quán)轉(zhuǎn)移到oc断凶,當(dāng)oc對(duì)象被ARC自動(dòng)回收的時(shí)候,c的CFRef指向null巫俺。

另外,如果c轉(zhuǎn)oc只使用__bridge肿男,則oc對(duì)象不持有c對(duì)象的引用介汹,被ARC回收的時(shí)候并不會(huì)讓引用計(jì)數(shù)-1,則需要CFRelease手動(dòng)釋放c對(duì)象舶沛。

一般見不到__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發(fā)生錯(cuò)誤,代碼goto到_out: 那么就需要手動(dòng)釋放data指針引用的c對(duì)象如庭。

而如果沒有錯(cuò)誤叹卷,那么把持有權(quán)轉(zhuǎn)交給返回值的NSData的對(duì)象,則data的引用retain-1坪它,接收返回值的指針變量retain+1骤竹,這樣就可以通過ARC來控制釋放了。

另外一個(gè)例子:

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對(duì)象的引用往毡,那么第一步和第二步完全可以不通過__bridge_transfer蒙揣,而是用CFStringRef來從第一行和第二行傳遞變量。

寫成這樣

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

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

但這樣就要通過CFRelease(UTI)釋放开瞭,而使用__bridge_transfer就不用管UTI的引用計(jì)數(shù)了懒震。

參考:http://www.reibang.com/p/82cbacc7e07b

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末罩息,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子个扰,更是在濱河造成了極大的恐慌瓷炮,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件递宅,死亡現(xiàn)場(chǎng)離奇詭異娘香,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)恐锣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門茅主,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人土榴,你說我怎么就攤上這事诀姚。” “怎么了玷禽?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵赫段,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我矢赁,道長(zhǎng)糯笙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任撩银,我火速辦了婚禮给涕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘额获。我一直安慰自己够庙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布抄邀。 她就那樣靜靜地躺著耘眨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪境肾。 梳的紋絲不亂的頭發(fā)上剔难,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音奥喻,去河邊找鬼偶宫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛环鲤,可吹牛的內(nèi)容都是我干的读宙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼楔绞,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼结闸!你這毒婦竟也來了唇兑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桦锄,失蹤者是張志新(化名)和其女友劉穎扎附,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體结耀,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡留夜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了图甜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碍粥。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖黑毅,靈堂內(nèi)的尸體忽然破棺而出嚼摩,到底是詐尸還是另有隱情,我是刑警寧澤矿瘦,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布枕面,位于F島的核電站,受9級(jí)特大地震影響缚去,放射性物質(zhì)發(fā)生泄漏潮秘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一易结、第九天 我趴在偏房一處隱蔽的房頂上張望枕荞。 院中可真熱鬧,春花似錦搞动、人聲如沸买猖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至飞主,卻和暖如春狮惜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碌识。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工碾篡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筏餐。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓开泽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親魁瞪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子穆律,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容