(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