C 指針和OC 對象之間的轉(zhuǎn)換方法
Core Foundation 框架
Core Foundation 框架 (CoreFoundation.framework) 是一組 C 語言接口, 簡稱 CF.
它們?yōu)?iOS 應(yīng)用程序提供基本數(shù)據(jù)管理和服務(wù)功能.
如 Core Graphics、Core Text,并且我們可能需要將 CF 對象和OC 對象進(jìn)行相互轉(zhuǎn)化,ARC 下,編譯器不會自動管理 CF 對象的內(nèi)存,我們需要手動管理.
創(chuàng)建一個 CF 對象使用后, 需要使用 CFRelease 將其手動釋放, 換句話說, Core Foundation 對象類型不在 ARC 管理范疇內(nèi).
如何將 CF 和 OC 對象有效的結(jié)合起來, 在 ARC 環(huán)境下, 提供了 橋接 的技術(shù), 即 ARC 下 OC 對象和 Core Foundation 對象之間的橋梁.
ARC 橋接
ARC 下 C 指針與 OC 指針(對象)之間轉(zhuǎn)換, 一般會用到下面的方法.
__bridge_retained <#CF type#>)<#expression#> __bridge_transfer <#Objective-C type#>)<#expression#> __bridge <#type#>)<#expression#>
也就是所謂的 橋接, 它是 Object-C 在 ARC 環(huán)境下開發(fā)出來的一種用作轉(zhuǎn)換 C 指針跟 OC (類)指針的一種轉(zhuǎn)換技術(shù), 所以是 ARC 下的稱謂, 在 MRC 下沒有 橋接.
針對內(nèi)存管理問題,ARC 可以管理 Objective-C 對象, 但不支持 Core Foundation 對象的管理,所以轉(zhuǎn)換后要注意一個問題:誰來釋放使用后的對象.
結(jié)合 ARC 和 內(nèi)存管理, 下面分別介紹一下.
Core Foundation 對象必須使用 CFRetain 和 CFRelease 來進(jìn)行內(nèi)存管理.
當(dāng)使用 Objective-C 和 Core Foundation 對象相互轉(zhuǎn)換的時候,必須讓編譯器知道,到底由誰來負(fù)責(zé)釋放對象,是否交給 ARC 處理, 只有正確的處理,才能避免內(nèi)存泄漏和 double free 導(dǎo)致程序崩潰.
__bridge_retained <#CF type#>)<#expression#>
__bridge_retained 等同于 CFBridgingRetain()
.
將 Objective-C 對象轉(zhuǎn)換為 Core Foundation 對象,把對象所有權(quán)橋接給 Core Foundation 對象,同時剝奪 ARC 的管理權(quán),后續(xù)需要開發(fā)者使用 CFRelease 或者相關(guān)方法手動來釋放 CF 對象.
示例:
void *cPointer; NSObject *objc = [[NSObject alloc] init]; //將 OC 對象轉(zhuǎn)換為 C 指針 cPointer = (__bridge_retained void*)objc; //use cPointer ... //需要釋放資源 CFRelease(cPointer);
在 ARC 下, CFBridgingRetain 實(shí)現(xiàn)如下:
NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) { return (__bridge_retained CFTypeRef)X; }
關(guān)于 CFTypeRef, 如下:
typedef const CF_BRIDGED_TYPE(id) void * CFTypeRef;
所以 CFBridgingRetain 返回值是 const void * 類型的.
上面的示例可以改寫為:
const void *cPointer; const NSObject *objc = [[NSObject alloc] init]; cPointer = CFBridgingRetain(objc); //use cPointer ... CFRelease(cPointer);
__bridge_transfer <#Objective-C type#>)<#expression#>
__bridge_transfer 等同于 CFBridgingRelease()
.
將非 OC 對象轉(zhuǎn)換為 OC 對象,同時將對象的管理權(quán)交給 ARC,開發(fā)者無需手動管理內(nèi)存.
示例:
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); CFStringRef strUUID = CFUUIDCreateString(kCFAllocatorDefault, uuid); NSString *str = (__bridge_transfer NSString *)strUUID; //無需釋放 strUUID //CFRelease(strUUID); CFRelease(uuid);
CFBridgingRelease 實(shí)現(xiàn)如下:
NS_INLINE id _Nullable CFBridgingRelease(CFTypeRef CF_CONSUMED _Nullable X) { return (__bridge_transfer id)X; }
上面的示例可以改寫為:
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); CFStringRef strUUID = CFUUIDCreateString(kCFAllocatorDefault, uuid); NSString *str = CFBridgingRelease(strUUID); //無需釋放 strUUID //CFRelease(strUUID); CFRelease(uuid);
__bridge
__bridge 不改變對象所有權(quán), 需要我們自己來管理內(nèi)存, 它也是我們經(jīng)常使用的方法, 從某種程度上來說, 它是上面兩個方法的簡化版本.
__bridge 可以將 OC 對象 與 C 指針相互轉(zhuǎn)換, 示例:
//CFString -> OC 對象 CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "very", kCFStringEncodingUTF8); NSString *nsString = (__bridge NSString *)cfString; NSLog(@"CFString -> NSString: %@", nsString); CFRelease(cfString);
如果將 CFRelease(cfString)
注釋掉, Xcode 的靜態(tài)檢測器會告訴你有內(nèi)存泄露的情況, 如圖:
再來另外一個例子, 如下:
//OC 對象 -> CFString NSString *nstr = @"itman"; CFStringRef cfStringRef = (__bridge CFStringRef)nstr; NSLog(@"NSString -> CFString: %@", cfStringRef); CFRelease(cfStringRef);
無論是使用 CFRelease(cfStringRef)
, 還是注釋掉, 靜態(tài)檢測器都不會報錯. 說明這種情況下, 當(dāng)前的內(nèi)存管理已經(jīng)被 OC 對象管理.
野指針
運(yùn)行下面的示例:
void *p; { NSObject *objc = [[NSObject alloc] init]; p = (__bridge void*)objc; } NSLog(@"mark: %@", (__bridge NSObject*)p);
會直接 crash, 如圖:
當(dāng) objc 這個對象超出作用域范圍,其內(nèi)存就會被回收,接著在作用域范圍外用 void *p 去訪問 objc 的內(nèi)存,就造成了野指針.
結(jié)合上面所說的, 我們可以讓指針 p 對 objc 進(jìn)行引用即 retain 操作, 修改如下:
void *p; { NSObject *objc = [[NSObject alloc] init]; //p = (__bridge void*)objc; p = (__bridge_retained void*)objc; } NSLog(@"mark: %@", (__bridge NSObject*)p); // 一定要釋放 CFRelease(p);
可以正常的運(yùn)行. 還可以修改為另一種方式:
void *p; { NSObject *objc = [[NSObject alloc] init]; //p = (__bridge void*)objc; //p = (__bridge_retained void*)objc; p = (void *)CFBridgingRetain(objc); } NSLog(@"mark: %@", (__bridge NSObject*)p); // 一定要釋放 CFRelease(p);
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對我們的支持。
您可能感興趣的文章
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對數(shù)怎么表達(dá)
- 01-10求子數(shù)組最大和的解決方法詳解
- 01-10深入理解數(shù)組指針與指針數(shù)組的區(qū)別
- 01-10基于C++輸出指針自增(++)運(yùn)算的示例分析
- 01-10基于errno返回值的對應(yīng)錯誤碼的詳細(xì)介紹
- 01-10用C實(shí)現(xiàn)添加和讀取配置文件函數(shù)
- 01-10解析sizeof, strlen, 指針以及數(shù)組作為函數(shù)參數(shù)的應(yīng)用
- 01-10探討C++中數(shù)組名與指針的用法比較分析
- 01-10深入理解雙指針的兩種用法
- 01-10深入串的模式匹配算法(普通算法和KMP算法)的詳解


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery