简介
Foundation与Core Foundation是两个关联密切的框架,区别主要在于Foundation是以Objective-C实现的,Core Foundation是以C语言实现的。在编程中有时会遇到两个框架内做类型转换,比如NSDictionary与CFDictionary之间的转换。
MRC
在MRC模式下,由于id类型其实也是指向结构体的一个指针,所以可以像C语言一样做类型转换,自己做好内存管理即可。如下:
NSDictionary *nDict = @{@"key" : @"value"};
CFDictionaryRef cDict = nDict;
NSDictionary *nDictOther = cDict;
ARC
在ARC模式下,编译器会为我们做内存管理,但是在遇到这种类型转换的时候,编译器无法判断该怎么处理这种对象的内存管理,即ARC没有办法处理Core Foundation框架下的内存管理问题。所以便有了下面几个关键字:
__bridge
__bridge_retained
__bridge_transfer
上述三个关键字的区别在于对象的内存管理权的处理
名称 | 描述 |
---|---|
__bridge | 只做类型转换,内存管理权不变 |
__bridge_retained | 将Foundation对象转换为CoreFoundation对象,交出内存管理权,需要做CFRelease操作,避免内存泄漏 |
__bridge_transfer | 将CoreFoundation对象转为Foundation对象,内存管理权交出,归ARC处理 |
__bridge
NSDictionary *dict = @{@"key" : @"value"};
CFDictionaryRef cfDict = (__bridge CFDictionaryRef)dict;
dict = nil;
NSLog(@"%@", cfDict);//这时这里会出现EXC_BAD_ACCESS,即访问了野指针。
但是使用NSString
时需要注意:
NSString *nsString = @"123";
CFStringRef cfString = (__bridge NSString *)nsString;
nsString = nil;
NSLog(@"%@", cfString);//使用string的这个例子,这么用没有问题
相当于__unsafe_unretained,nsString被设置为nil后,cfString会变成野指针?需确定。
经过确定,只使用__bridge时,的确会在原oc变量释放后cf对象变成野指针的情况,但是不能用NSString
这个例子来讲,因为NSString
的引用计数受到系统的特殊处理,具体参考链接。
__bridge_retained
NSDictionary *nDdict = @{@"key" : @"value"};
CFDictionaryRef cDict = (__bridge_retained CFDictionaryRef)nDict;
nDict = nil;
NSLog(@"%@", cDict);//这时是没问题的
...
CFRelease(cDict);
nDict不再持有内存的管理权,nDict即使设置为nil,也不会影响cDict对内存的引用,需要开发者找个合适的时机去调用CFRelease(cDict)来释放。
__bridge_transfer
CFDictionaryRef cDict = CFDictionaryCreate(CFAllocatorGetDefault(), &("key"), &("value"), 1, NULL, NULL);
NSDictionary *nDict = (__bridge_transfer NSDictionary *)cDict;
//nDict = CFBridgingRelease(cDict);也可以直接用这个函数
cDict对内存的管理权移交给nDict,即ARC来处理。