iOS允許Objective-C 和 Core Foundation 對象之間可以輕松的轉(zhuǎn)換慢宗,拿 NSString 和 CFStringRef 來說昧谊,直接轉(zhuǎn)換豪無壓力:
CFStringRef aCFString = (CFStringRef)aNSString;
NSString *aNSString = (NSString *)aCFString;
針對內(nèi)存管理問題每币,ARC 可以幫忙管理 Objective-C 對象, 但是不支持 Core Foundation 對象的管理力麸,所以轉(zhuǎn)換后要注意一個問題:誰來釋放使用后的對象拐辽。 本文重點(diǎn)總結(jié)一下類型轉(zhuǎn)換后的內(nèi)存管理磁滚。
一佛吓、非ARC的內(nèi)存管理
倘若不使用ARC,手動管理內(nèi)存垂攘,思路比較清晰维雇,使用完,release轉(zhuǎn)換后的對象即可晒他。
//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的誕生大大簡化了我們針對內(nèi)存管理的開發(fā)工作,但是只支持管理 Objective-C 對象, 不支持 Core Foundation 對象陨仅。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)致程序崩潰锌介。
根據(jù)不同需求,有3種轉(zhuǎn)換方式
__bridge ? ? ? ? ? ? ? ? ? ? ? ?(不改變對象所有權(quán))
__bridge_retained 或者 CFBridgingRetain() ? ? ? ? ? ? ? (解除 ARC 所有權(quán))
__bridge_transfer 或者 CFBridgingRelease() ? ? ? ? ? ? (給予 ARC 所有權(quán))
1. __bridge_retained 或者 CFBridgingRetain()
__bridge_retained 或者 CFBridgingRetain() ?將Objective-C對象轉(zhuǎn)換為Core Foundation對象猾警,把對象所有權(quán)橋接給Core Foundation對象孔祸,同時剝奪ARC的管理權(quán),后續(xù)需要開發(fā)者使用CFRelease或者相關(guān)方法手動來釋放對象发皿。
來看個例子:
- (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 的宏方法,下面兩行代碼等價:
CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;
CFStringRef aCFString = (CFStringRef) CFBridgingRetain(aNSString);
2. __bridge_transfer 或者 CFBridgingRelease()
__bridge_transfer 或者 CFBridgingRelease() ?將非Objective-C對象轉(zhuǎn)換為Objective-C對象穴墅,同時將對象的管理權(quán)交給ARC惶室,開發(fā)者無需手動管理內(nèi)存。
接著上面那個內(nèi)存泄漏的例子玄货,再轉(zhuǎn)成OC對象交給ARC來管理內(nèi)存皇钞,無需手動管理,也不會出現(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的宏方法松捉,下面兩行代碼等價:
aNSString = (__bridge_transfer NSString *)aCFString;
aNSString = (NSString *)CFBridgingRelease(aCFString);
3. __bridge
__bridge 只做類型轉(zhuǎn)換夹界,不改變對象所有權(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ā)者手動釋放,不歸ARC管:
- (void)viewDidLoad
{
[super viewDidLoad];
CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII);
NSString *aNSString = (__bridge NSString *)aCFString;
(void)aNSString;
CFRelease(aCFString);
}