本文轉至: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。
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 關鍵字。
總結:
- Core Foundation 對象類型不在 ARC 管理范疇內
- Cocoa Framework::Foundation 對象類型(即一般使用到的Objectie-C對象類型)在 ARC 的管理范疇內
3. bridge, bridge_transfer和__bridge_retained 是CF和OC的橋梁 - 如果不在 ARC 管理范疇內的對象,那么要清楚 release 的責任應該是誰以及各種對象的生命周期是怎么樣的
這是目前在學習ImageIO蘋果官方提供的圖片解碼器,遇到OC和CF之間相互轉化的一些問題,重新整理,細致的了解下,以方便后期更加深入的學習。