iOS-淺談__bridge

淺談__bridge牲览,__bridge_retained墓陈,__bridge_transfer
通過OC對象與C語言轉(zhuǎn)換

通過OC對象與CF對象(Core Foundation)轉(zhuǎn)換來進行淺談。

基本概念

__bridge:只涉及對象類型轉(zhuǎn)換不涉及對象所有權(quán)的轉(zhuǎn)換第献;
__bridge_retained:OC對象轉(zhuǎn)換成CF對象贡必,將OC對象所有權(quán)交給CF對象,內(nèi)存需要自己管理庸毫;
__bridge_transfer:CF對象轉(zhuǎn)換成OC對象仔拟,將CF對象所有權(quán)交給OC對象,ARC可以自動管理內(nèi)存飒赃;

ARC環(huán)境下編譯器會自動管理OC對象的內(nèi)存利花,但是不會自動管理CF對象的內(nèi)存,當我們創(chuàng)建了一個CF對象以后就需要我們使用CFRelease將其手動釋放

以下通過代碼來說明:

id類型和void *類型的轉(zhuǎn)換

__bridge

在MRC下载佳,id類型和void *類型的轉(zhuǎn)換

id obj = [[NSObject alloc] init];
void *pointer = obj;
obj = pointer;

上面這段代碼放在ARC下炒事,會報錯。


id轉(zhuǎn)void*.png
void*轉(zhuǎn)id.png

id與void *如果只是單純的類型轉(zhuǎn)換蔫慧,那么只要添加__bridge即可挠乳,不會改變對象所有權(quán)。
另外CFBridgingRetain和CFBridgingRelease將在下面介紹。

ARC代碼如下:

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

\color{red}{注意:此時的指針變量pointer并沒有持有對象睡扬,所以要注意野指針的問題}

如下代碼盟蚣,就會造成野指針

void *pointer = NULL;

{
    id obj = [[NSObject alloc] init];
    pointer = (__bridge void *)obj;
    //代碼塊執(zhí)行完畢后,obj對象已經(jīng)自動釋放威蕉,此時指針變量pointer指向的是一塊被釋放的內(nèi)存空間
}
//打印引用計數(shù)的時候就會報野指針錯誤
NSLog(@"retain count:%ld", CFGetRetainCount((__bridge CFTypeRef)((__bridge id)pointer)));
__bridge_retained

ARC代碼如下:

void *pointer = NULL;
{
    id obj = [[NSObject alloc] init];
    pointer = (__bridge_retained void *)obj;
}
NSLog(@"retain count:%ld", CFGetRetainCount((__bridge CFTypeRef)((__bridge id)pointer)));  //retain count:1

通過打印結(jié)果刁俭,我看可以看到指針變量pointer仍然指向一個有效的實體。說明它擁有該對象的所有權(quán)韧涨。

MRC代碼如下:

void *pointer = NULL;
{
    id obj = [[NSObject alloc] init]; //retain count:1
    pointer = [obj retain];  //retain count:2
    [obj release];  //retain count:1
}
NSLog(@"retain count:%ld", [(id)pointer retainCount]);  //retain count:1

結(jié)論: __bridge_retained,可使要轉(zhuǎn)換賦值的對象也持有所賦值的對象侮繁。

__bridge_transfer

ARC代碼如下:

void *pointer = NULL;
{
    id obj = [[NSObject alloc] init];
    pointer = (__bridge_retained void *)obj;
}
//pointer持有對象
id object = (__bridge_transfer id)pointer;

MRC代碼如下:

void *pointer = NULL;
{
    id obj = [[NSObject alloc] init]; //retain count:1
    pointer = [obj retain];  //retain count:2
    [obj release];  //retain count:1
}
id object = (id)pointer;  //retain count:1
[object retain];  //retain count:2
[(id)pointer release];  //retain count:1

結(jié)論: __bridge_transfer虑粥,被轉(zhuǎn)換賦值的對象賦值給變量后,隨即也自行釋放宪哩。

聲明 id object 的時候娩贷,其實是缺省的申明了一個 __strong 修飾的變量,所以編譯器自動地加入了 retain 的處理锁孟,所以說 __bridge_transfer 關(guān)鍵字只為我們做了 release 處理彬祖。

OC對象和CF對象(Core Foundation)的轉(zhuǎn)換

Core Foundation 對象主要是由C語言實現(xiàn)的,其中也有對象引用計數(shù)的概念品抽,只不過不是retain/release储笑,而是自身的 CFRetain/CFRelease。

其中有一個概念:Toll-Free Bridging
它表示的是在Core Foundation框架和Foundation框架之間交換使用數(shù)據(jù)類型的技術(shù)圆恤。

#if __has_feature(objc_arc)

// After using a CFBridgingRetain on an NSObject, the caller must take responsibility for calling CFRelease at an appropriate time.
NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) {
    return (__bridge_retained CFTypeRef)X;
}

NS_INLINE id _Nullable CFBridgingRelease(CFTypeRef CF_CONSUMED _Nullable X) {
    return (__bridge_transfer id)X;
}

#else

// This function is intended for use while converting to ARC mode only.
NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) {
    return X ? CFRetain((CFTypeRef)X) : NULL;
}

// This function is intended for use while converting to ARC mode only.
NS_INLINE id _Nullable CFBridgingRelease(CFTypeRef CF_CONSUMED _Nullable X) {
    return [(id)CFMakeCollectable(X) autorelease];
}

#endif

我們可以看到CFBridgingRetain和CFBridgingRelease突倍,其實就是__bridge_retained和__bridge_transfer。

并不是所有的CF對象都支持Toll-Free Bridging
我們可以參照蘋果文檔盆昙,查看可支持的類型表羽历。

下面是簡單的代碼示例:

__bridge

MRC代碼如下:

NSString *string = [NSString stringWithFormat:@"hui"];
CFStringRef stringRef = (CFStringRef)string;

上面代碼如果直接用在ARC,會報錯淡喜,可以自己嘗試秕磷。

然后

ARC代碼如下:

NSString *string = [NSString stringWithFormat:@"hui"];
CFStringRef stringRef = (__bridge CFStringRef)string;
CFBridgingRetain - OC對象轉(zhuǎn)CF對象
NSString *string = [NSString stringWithFormat:@"hui"];
CFStringRef stringRef = CFBridgingRetain(string);

// 由于CF對象不屬于ARC的管理,所以需要自己release
CFRelease(stringRef);

CFBridgingRelease - CF對象轉(zhuǎn)OC對象
CFStringRef stringRef = CFStringCreateWithCString(kCFAllocatorDefault, "hui", kCFStringEncodingUTF8);
NSString *string = CFBridgingRelease(stringRef);

//CFRelease(stringRef);  使用CFBridgingRelease轉(zhuǎn)移了對象所有權(quán)炼团,所以不用調(diào)用CFRelease

總結(jié)

  1. Core Foundation 對象類型不在 ARC 管理范疇澎嚣,所以需要自己手動釋放;
  2. __bridge只更改對象類型们镜,不會涉及對象所有權(quán)币叹,使用它時要注意野指針的情況;
  3. __bridge_retained(CFBridgingRetain)是將OC對象轉(zhuǎn)換成C語言變量或者CF對象模狭,類似于retain颈抚,可使要轉(zhuǎn)換賦值的對象也持有所賦值的對象;
  4. __bridge_transfer(CFBridgingRelease)是將C語言變量或者CF對象轉(zhuǎn)換成OC對象,類似于release贩汉,被轉(zhuǎn)換賦值的對象賦值給變量后驱富,隨即也自行釋放;

over!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匹舞,一起剝皮案震驚了整個濱河市褐鸥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赐稽,老刑警劉巖叫榕,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異姊舵,居然都是意外死亡晰绎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門括丁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荞下,“玉大人,你說我怎么就攤上這事史飞〖饣瑁” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵构资,是天一觀的道長抽诉。 經(jīng)常有香客問我,道長蚯窥,這世上最難降的妖魔是什么掸鹅? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮拦赠,結(jié)果婚禮上巍沙,老公的妹妹穿的比我還像新娘。我一直安慰自己荷鼠,他們只是感情好句携,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著允乐,像睡著了一般矮嫉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牍疏,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天蠢笋,我揣著相機與錄音,去河邊找鬼鳞陨。 笑死昨寞,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播援岩,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼歼狼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了享怀?” 一聲冷哼從身側(cè)響起羽峰,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎添瓷,沒想到半個月后梅屉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡鳞贷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年履植,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悄晃。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖凿滤,靈堂內(nèi)的尸體忽然破棺而出妈橄,到底是詐尸還是另有隱情,我是刑警寧澤翁脆,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布眷蚓,位于F島的核電站,受9級特大地震影響反番,放射性物質(zhì)發(fā)生泄漏沙热。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一罢缸、第九天 我趴在偏房一處隱蔽的房頂上張望篙贸。 院中可真熱鬧,春花似錦枫疆、人聲如沸爵川。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寝贡。三九已至,卻和暖如春值依,著一層夾襖步出監(jiān)牢的瞬間圃泡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工愿险, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留颇蜡,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像澡匪,于是被迫代替她去往敵國和親熔任。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

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