Objective-C 和 Core Foundation 對(duì)象相互轉(zhuǎn)換的內(nèi)存管理總結(jié)

iOS允許Objective-C 和 Core Foundation 對(duì)象之間可以輕松的轉(zhuǎn)換,拿 NSString 和 CFStringRef 來(lái)說(shuō),直接轉(zhuǎn)換豪無(wú)壓力:

CFStringRef aCFString = (CFStringRef)aNSString;

NSString *aNSString = (NSString *)aCFString;

針對(duì)內(nèi)存管理問(wèn)題,ARC 可以幫忙管理 Objective-C 對(duì)象, 但是不支持 Core Foundation 對(duì)象的管理,所以轉(zhuǎn)換后要注意一個(gè)問(wèn)題:誰(shuí)來(lái)釋放使用后的對(duì)象。 本文重點(diǎn)總結(jié)一下類型轉(zhuǎn)換后的內(nèi)存管理。

一、非ARC的內(nèi)存管理

倘若不使用ARC,手動(dòng)管理內(nèi)存,思路比較清晰,使用完,release轉(zhuǎn)換后的對(duì)象即可。

//NSString 轉(zhuǎn) CFStringRef

CFStringRef aCFString = (CFStringRef) [[NSString alloc] initWithFormat:@"%@", string];

//...

CFRelease(aCFString);

//CFStringRef 轉(zhuǎn) NSString

CFStringRef aCFString = CFStringCreateWithCString(kCFAllocatorDefault,

bytes,

NSUTF8StringEncoding);

NSString *aNSString = (NSString *)aCFString;

//...

[aNSString release];

二、ARC下的內(nèi)存管理

ARC的誕生大大簡(jiǎn)化了我們針對(duì)內(nèi)存管理的開發(fā)工作,但是只支持管理 Objective-C 對(duì)象, 不支持 Core Foundation 對(duì)象。Core Foundation 對(duì)象必須使用CFRetain和CFRelease來(lái)進(jìn)行內(nèi)存管理。那么當(dāng)使用Objective-C 和 Core Foundation 對(duì)象相互轉(zhuǎn)換的時(shí)候,必須讓編譯器知道,到底由誰(shuí)來(lái)負(fù)責(zé)釋放對(duì)象,是否交給ARC處理。只有正確的處理,才能避免內(nèi)存泄漏和double free導(dǎo)致程序崩潰。

根據(jù)不同需求,有3種轉(zhuǎn)換方式

__bridge ? ? ? ? ? ? ? ? ? ? ? ?(不改變對(duì)象所有權(quán))

__bridge_retained 或者 CFBridgingRetain() ? ? ? ? ? ? ? (解除 ARC 所有權(quán))

__bridge_transfer 或者 CFBridgingRelease() ? ? ? ? ? ? (給予 ARC 所有權(quán))

1. __bridge_retained 或者 CFBridgingRetain()

__bridge_retained 或者 CFBridgingRetain() ?將Objective-C對(duì)象轉(zhuǎn)換為Core Foundation對(duì)象,把對(duì)象所有權(quán)橋接給Core Foundation對(duì)象,同時(shí)剝奪ARC的管理權(quán),后續(xù)需要開發(fā)者使用CFRelease或者相關(guān)方法手動(dòng)來(lái)釋放對(duì)象。

來(lái)看個(gè)例子:

- (void)viewDidLoad

{

[super viewDidLoad];

NSString *aNSString = [[NSString alloc]initWithFormat:@"test"];

CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;

(void)aCFString;

//正確的做法應(yīng)該執(zhí)行CFRelease

//CFRelease(aCFString);

}

程序沒有執(zhí)行CFRelease,造成內(nèi)存泄漏:

CFBridgingRetain() ?是 __bridge_retained 的宏方法,下面兩行代碼等價(jià):

CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;

CFStringRef aCFString = (CFStringRef) CFBridgingRetain(aNSString);

2. __bridge_transfer 或者 CFBridgingRelease()

__bridge_transfer 或者 CFBridgingRelease() ?將非Objective-C對(duì)象轉(zhuǎn)換為Objective-C對(duì)象,同時(shí)將對(duì)象的管理權(quán)交給ARC,開發(fā)者無(wú)需手動(dòng)管理內(nèi)存。

接著上面那個(gè)內(nèi)存泄漏的例子,再轉(zhuǎn)成OC對(duì)象交給ARC來(lái)管理內(nèi)存,無(wú)需手動(dòng)管理,也不會(huì)出現(xiàn)內(nèi)存泄漏:

- (void)viewDidLoad

{

[super viewDidLoad];

NSString *aNSString = [[NSString alloc]initWithFormat:@"test"];

CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;

aNSString = (__bridge_transfer NSString *)aCFString;

}

CFBridgingRelease() 是__bridge_transfer的宏方法,下面兩行代碼等價(jià):

aNSString = (__bridge_transfer NSString *)aCFString;

aNSString = (NSString *)CFBridgingRelease(aCFString);

3. __bridge

__bridge 只做類型轉(zhuǎn)換,不改變對(duì)象所有權(quán),是我們最常用的轉(zhuǎn)換符。

從OC轉(zhuǎn)CF,ARC管理內(nèi)存:

- (void)viewDidLoad

{

[super viewDidLoad];

NSString *aNSString = [[NSString alloc]initWithFormat:@"test"];

CFStringRef aCFString = (__bridge CFStringRef)aNSString;

(void)aCFString;

}

從CF轉(zhuǎn)OC,需要開發(fā)者手動(dòng)釋放,不歸ARC管:

- (void)viewDidLoad

{

[super viewDidLoad];

CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII);

NSString *aNSString = (__bridge NSString *)aCFString;

(void)aNSString;

CFRelease(aCFString);

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容