iOS開發之__bridge,__bridge_transfer和__bridge_retained


 

本文轉至:http://www.qingpingshan.com/rjbc/ios/157477.html

引言

Core Foundation框架 (CoreFoundation.framework) 是一組C語言接口,它們為iOS應用程序提供基本數據管理和服務功能。下面列舉該框架支持進行管理的數據以及可提供的服務:

1.群體數據類型 (數組、集合等)

2.程序包

3.字符串管理

4.日期和時間管理

5.原始數據塊管理

6.偏好管理

7.URL及數據流操作

8.線程和RunLoop

9.端口和soket通訊

Core Foundation框架和Foundation框架緊密相關,它們為相同功能提供接口,但Foundation框架提供Objective-C接口。如果您將Foundation對象和Core Foundation類型摻雜使用,則可利用兩個框架之間的 “toll-free bridging”。所謂的Toll-free bridging是說您可以在某個框架的方法或函數同時使用Core Foundatio和Foundation 框架中的某些類型。很多數據類型支持這一特性,其中包括群體和字符串數據類型。每個框架的類和類型描述都會對某個對象是否為 toll-free bridged,應和什么對象橋接進行說明。

Toll-free bridging 是ARC下OC對象和Core Foundation對象之間的橋梁

在開發iOS應用程序時我們有時會用到Core Foundation對象,下面簡稱CF。例如Core Graphics、Core Text,並且我們可能需要將CF對象和OC對象進行相互轉化,我們知道,ARC環境下,編譯器不會自動管理CF對象的內存,我們需要手動管理。這就是我們在創建一個CF對象以后需要我們使用CFRelease將其手動釋放。

那么CF和OC相互轉化的時候該如何管理內存呢?

我們可以通過 bridge, bridge_transfer,__bridge_retained 來進行內存管理

1.__bridge

CF和OC對象轉化時只涉及對象類型不涉及對象所有權的轉化

//Image I/O 從 NSBundle 讀取圖片數據 NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"]; CGImageSourceRef source = CGImageSourceCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"]], NULL);

如果上面不添加 bridge ,在ARC環境下,系統會給出錯誤提示和錯誤修正,點擊錯誤提示的話,系統會為我們自動添加 bridge ,因為在OC與CF的轉化時只涉及到對象類型沒有涉及到對象所有權的轉化,所以上述代碼不需要對CF的對象進行釋放,即不需要添加CFRelease

注釋: iOS ARC  ARC 之間的轉換方法 1,選擇項目中的Targets,選中你所要操作的Target 2,選Build Phases,在其中Complie Sources中選擇需要ARC的文件雙擊, 並在輸入框中輸入:-fobjc-arc,如果不要ARC則輸入:-fno-objc-arc

為了解決這一問題,我們使用 __bridge 關鍵字來實現id類型與void*類型的相互轉換。

id obj = [[NSObject alloc] init]; void *p = (__bridge void *)(obj); NSLog(@"obj retainCount %ld",[(id)p retainCount]);

輸出結果:

CFDemo[2932:777997] obj retainCount 1

2.__bridge_transfer

常用在CF對象轉化成OC對象時,將CF對象的所有權交給OC對象,此時ARC就能自動管理該內存,作用同CFBridgingRelease()

如果非ARC的時候,我們可能需要寫下面的代碼。

// p 變量原先持有對象的所有權 id obj = (id)p; [obj retain]; [(id)p release];

那么ARC有效后,我們可以用下面的代碼來替換:

// p 變量原先持有對象的所有權
id obj = (__bridge_transfer id)p;

可以看出來, bridge_retained 是編譯器替我們做了 retain 操作,而 bridge_transfer 是替我們做了 release。

3. 

bridge_retained

bridge_transfer 相反,常用在將OC對象轉化成CF對象,且OC對象的所有權也交給CF對象來管理,即OC對象轉化成CF對象時,涉及到對象類型和對象所有權的轉化,作用同CFBridgingRetain()

先來看使用 __bridge_retained 關鍵字的例子程序:

id obj = [[NSObject alloc] init]; void *p = (__bridge_retained void *)obj;

此時retainCount 會被加1;

從名字上我們應該能理解其意義:類型被轉換時,其對象的所有權也將被變換后變量所持有。如果不是ARC代碼,類似下面的實現:

id obj = [[NSObject alloc] init]; void *p = obj; [(id)p retain];

ARC如何獲取retainCount

NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)myObject));

來來來舉個例子:

NSString *string = [NSString stringWithFormat:@""]; CFStringRef cfString = (__bridge CFStringRef)string; CFStringRef cfStr = (__bridge_retained CFStringRef)string; CFRelease(cfString);// 由於Core Foundation的對象不屬於ARC的管理范疇,所以需要自己release CFRelease(cfStr);

使用 __bridge_retained 可以通過轉換目標處(cfStr)的 retain 處理,來使所有權轉移。即使 string 變量被釋放,cfString變量也變釋放,cfStr 還是可以使用具體的對象。只是有一點,由於Core Foundation的對象不屬於ARC的管理范疇,所以需要自己release。

CFStringRef cfString= CFURLCreateStringByAddingPercentEscapes( NULL, (__bridge CFStringRef)text, NULL, CFSTR("!*’();:@&=+$,/?%#[]"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)); NSString *ocString = (__bridge_transfer CFStringRef)cfString;

所有權被轉移的同時,被轉換變量將失去對象的所有權。當Core Foundation對象類型向Objective-C對象類型轉換的時候,會經常用到 __bridge_transfer 關鍵字。

總結:

  1. Core Foundation 對象類型不在 ARC 管理范疇內
  2. Cocoa Framework::Foundation 對象類型(即一般使用到的Objectie-C對象類型)在 ARC 的管理范疇內 
    3. bridge, bridge_transfer和__bridge_retained 是CF和OC的橋梁
  3. 如果不在 ARC 管理范疇內的對象,那么要清楚 release 的責任應該是誰以及各種對象的生命周期是怎么樣的

這是目前在學習ImageIO蘋果官方提供的圖片解碼器,遇到OC和CF之間相互轉化的一些問題,重新整理,細致的了解下,以方便后期更加深入的學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM