国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C 指針和OC 對象之間的轉換方法

2020-05-23 13:33:51
字體:
來源:轉載
供稿:網友

Core Foundation 框架

Core Foundation 框架 (CoreFoundation.framework) 是一組 C 語言接口, 簡稱 CF.

它們為 iOS 應用程序提供基本數據管理和服務功能.

如 Core Graphics、Core Text,并且我們可能需要將 CF 對象和OC 對象進行相互轉化,ARC 下,編譯器不會自動管理 CF 對象的內存,我們需要手動管理.

創建一個 CF 對象使用后, 需要使用 CFRelease 將其手動釋放, 換句話說, Core Foundation 對象類型不在 ARC 管理范疇內.

如何將 CF 和 OC 對象有效的結合起來, 在 ARC 環境下, 提供了 橋接 的技術, 即 ARC 下 OC 對象和 Core Foundation 對象之間的橋梁.

ARC 橋接

ARC 下 C 指針與 OC 指針(對象)之間轉換, 一般會用到下面的方法.

__bridge_retained <#CF type#>)<#expression#>__bridge_transfer <#Objective-C type#>)<#expression#>__bridge <#type#>)<#expression#>

也就是所謂的 橋接, 它是 Object-C 在 ARC 環境下開發出來的一種用作轉換 C 指針跟 OC (類)指針的一種轉換技術, 所以是 ARC 下的稱謂, 在 MRC 下沒有 橋接.

針對內存管理問題,ARC 可以管理 Objective-C 對象, 但不支持 Core Foundation 對象的管理,所以轉換后要注意一個問題:誰來釋放使用后的對象.

結合 ARC 和 內存管理, 下面分別介紹一下.

Core Foundation 對象必須使用 CFRetain 和 CFRelease 來進行內存管理.

當使用 Objective-C 和 Core Foundation 對象相互轉換的時候,必須讓編譯器知道,到底由誰來負責釋放對象,是否交給 ARC 處理, 只有正確的處理,才能避免內存泄漏和 double free 導致程序崩潰.

__bridge_retained <#CF type#>)<#expression#>

__bridge_retained 等同于 CFBridgingRetain() .

將 Objective-C 對象轉換為 Core Foundation 對象,把對象所有權橋接給 Core Foundation 對象,同時剝奪 ARC 的管理權,后續需要開發者使用 CFRelease 或者相關方法手動來釋放 CF 對象.

示例:

void *cPointer;NSObject *objc = [[NSObject alloc] init];//將 OC 對象轉換為 C 指針cPointer = (__bridge_retained void*)objc;//use cPointer ...//需要釋放資源CFRelease(cPointer);

在 ARC 下, CFBridgingRetain 實現如下:

NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) { return (__bridge_retained CFTypeRef)X;}

關于 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 對象轉換為 OC 對象,同時將對象的管理權交給 ARC,開發者無需手動管理內存.

示例:

CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);CFStringRef strUUID = CFUUIDCreateString(kCFAllocatorDefault, uuid);NSString *str = (__bridge_transfer NSString *)strUUID;//無需釋放 strUUID//CFRelease(strUUID);CFRelease(uuid);

CFBridgingRelease 實現如下:

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 不改變對象所有權, 需要我們自己來管理內存, 它也是我們經常使用的方法, 從某種程度上來說, 它是上面兩個方法的簡化版本.

__bridge 可以將 OC 對象 與 C 指針相互轉換, 示例:

//CFString -> OC 對象CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "very", kCFStringEncodingUTF8);NSString *nsString = (__bridge NSString *)cfString;NSLog(@"CFString -> NSString: %@", nsString);CFRelease(cfString);

如果將 CFRelease(cfString) 注釋掉, Xcode 的靜態檢測器會告訴你有內存泄露的情況, 如圖:

C,指針,OC,對象

再來另外一個例子, 如下:

//OC 對象 -> CFStringNSString *nstr = @"itman";CFStringRef cfStringRef = (__bridge CFStringRef)nstr;NSLog(@"NSString -> CFString: %@", cfStringRef);CFRelease(cfStringRef);

無論是使用 CFRelease(cfStringRef) , 還是注釋掉, 靜態檢測器都不會報錯. 說明這種情況下, 當前的內存管理已經被 OC 對象管理.

野指針

運行下面的示例:

void *p;{ NSObject *objc = [[NSObject alloc] init]; p = (__bridge void*)objc;}NSLog(@"mark: %@", (__bridge NSObject*)p);

會直接 crash, 如圖:

C,指針,OC,對象

當 objc 這個對象超出作用域范圍,其內存就會被回收,接著在作用域范圍外用 void *p 去訪問 objc 的內存,就造成了野指針.

結合上面所說的, 我們可以讓指針 p 對 objc 進行引用即 retain 操作, 修改如下:

void *p;{ NSObject *objc = [[NSObject alloc] init]; //p = (__bridge void*)objc; p = (__bridge_retained void*)objc;}NSLog(@"mark: %@", (__bridge NSObject*)p); // 一定要釋放CFRelease(p);

可以正常的運行. 還可以修改為另一種方式:

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);

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 黄冈市| 库车县| 从化市| 青河县| 舟山市| 分宜县| 新民市| 乾安县| 沙田区| 汕头市| 达日县| 湖口县| 屯留县| 梧州市| 长丰县| 霍州市| 新余市| 郑州市| 盐亭县| 精河县| 衡水市| 获嘉县| 苍山县| 双流县| 永平县| 洞口县| 贵溪市| 家居| 西昌市| 县级市| 南投市| 凤阳县| 德钦县| 彩票| 荆州市| 株洲市| 新巴尔虎右旗| 尼勒克县| 农安县| 保定市| 台安县|