標籤:
轉載自:http://www.cocoachina.com/industry/20130411/5975.html Objective-C和Core Foundation 對象相互轉換的記憶體管理總結
發佈於:2013-04-11 13:37閱讀數:4109
iOS允許Objective-C 和 Core Foundation 對象之間可以輕鬆的轉換,拿 NSString 和 CFStringRef 來說,直接轉換毫無壓力: [cpp] view plaincopyprint? 01. CFStringRef aCFString = (CFStringRef)aNSString; 02. NSString *aNSS
“” 閱讀器
iOS允許Objective-C 和 Core Foundation 對象之間可以輕鬆的轉換,拿 NSString 和 CFStringRef 來說,直接轉換毫無壓力:
[cpp] view plaincopyprint?
01. CFStringRef aCFString = (CFStringRef)aNSString;
02. NSString *aNSString = (NSString *)aCFString;
針對記憶體管理問題,ARC 可以幫忙管理 Objective-C 對象, 但是不支援 Core Foundation 對象的管理,所以轉換後要注意一個問題:誰來釋放使用後的對象。 本文重點總結一下類型轉換後的記憶體管理。
一、非ARC的記憶體管理
倘若不使用ARC,手動管理記憶體,思路比較清晰,使用完,release轉換後的對象即可。
[cpp] view plaincopyprint?
01. //NSString 轉 CFStringRef
02. CFStringRef aCFString = (CFStringRef) [[NSString alloc] initWithFormat:@"%@", string];
03. //...
04. CFRelease(aCFString);
05.
06.
07. //CFStringRef 轉 NSString
08. CFStringRef aCFString = CFStringCreateWithCString(kCFAllocatorDefault,
09. bytes,
10. NSUTF8StringEncoding);
11. NSString *aNSString = (NSString *)aCFString;
12. //...
13. [aNSString release];
二、ARC下的記憶體管理
ARC的誕生大大簡化了我們針對記憶體管理的開發工作,但是只支援管理 Objective-C 對象, 不支援 Core Foundation 對象。Core Foundation 對象必須使用CFRetain和CFRelease來進行記憶體管理。那麼當使用Objective-C 和 Core Foundation 對象相互轉換的時候,必須讓編譯器知道,到底由誰來負責釋放對象,是否交給ARC處理。只有正確的處理,才能避免記憶體流失和double free導致程式崩潰。
根據不同需求,有3種轉換方式
•__bridge (不改變對象所有權)
•__bridge_retained 或者 CFBridgingRetain() (解除 ARC 所有權)
•__bridge_transfer 或者 CFBridgingRelease() (給予 ARC 所有權)
1. __bridge_retained 或者 CFBridgingRetain()
__bridge_retained 或者 CFBridgingRetain() 將Objective-C對象轉換為Core Foundation對象,把對象所有權橋接給Core Foundation對象,同時剝奪ARC的管理權,後續需要開發人員使用CFRelease或者相關方法手動來釋放對象。
例子:
[cpp] view plaincopyprint?
01. - (void)viewDidLoad
02. {
03. [super viewDidLoad];
04.
05. NSString *aNSString = [[NSString alloc]initWithFormat:@"test"];
06. CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;
07.
08. (void)aCFString;
09.
10. //正確的做法應該執行CFRelease
11. //CFRelease(aCFString);
12.}
程式沒有執行CFRelease,造成記憶體流失:
CFBridgingRetain() 是 __bridge_retained 的宏方法,下面兩行代碼等價:
[cpp] view plaincopyprint?
01. CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;
02. CFStringRef aCFString = (CFStringRef) CFBridgingRetain(aNSString);
2. __bridge_transfer 或者 CFBridgingRelease()
__bridge_transfer 或者 CFBridgingRelease() 將非Objective-C對象轉換為Objective-C對象,同時將對象的管理權交給ARC,開發人員無需手動管理記憶體。
接著上面那個記憶體流失的例子,再轉成OC對象交給ARC來管理記憶體,無需手動管理,也不會出現記憶體流失:
[cpp] view plaincopyprint?
01. - (void)viewDidLoad
02. {
03. [super viewDidLoad];
04.
05. NSString *aNSString = [[NSString alloc]initWithFormat:@"test"];
06. CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;
07. aNSString = (__bridge_transfer NSString *)aCFString;
08. }
CFBridgingRelease() 是__bridge_transfer的宏方法,下面兩行代碼等價:
[cpp] view plaincopyprint?
01. aNSString = (__bridge_transfer NSString *)aCFString;
02. aNSString = (NSString *)CFBridgingRelease(aCFString);
3. __bridge
__bridge 只做類型轉換,不改變對象所有權,是我們最常用的轉換符。
從OC轉CF,ARC管理記憶體:
[cpp] view plaincopyprint?
01. - (void)viewDidLoad
02. {
03. [super viewDidLoad];
04.
05. NSString *aNSString = [[NSString alloc]initWithFormat:@"test"];
06. CFStringRef aCFString = (__bridge CFStringRef)aNSString;
07.
08. (void)aCFString;
09. }
從CF轉OC,需要開發人員手動釋放,不歸ARC管:
[cpp] view plaincopyprint?
01. - (void)viewDidLoad
02.
03. [super viewDidLoad];
04.
05. CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII);
06. NSString *aNSString = (__bridge NSString *)aCFString;
07.
08. (void)aNSString;
09.
10. CFRelease(aCFString);
11. }
ios 中__bridge,__bridge_transfer和__bridge_retained詳解