Core Foundation对象的内存管理
2018-03-09 本文已影响87人
_Joeyoung_
Core Foundation 对象主要使用在C语言编写的 Core Foundation 框架中,并使用引用计数的对象。在 MRC(Manaual Reference Counting)中,Core Foundation 框架中的 retain/release 分别是 CFRetain/CFRelease。
Core Foundation 对象与 Objective-C 对象的区别很小,不同之处只是在于是由哪一个框架(Foundation 框架还是 Core Foundation 框架)所生成的。无论哪个框架生成,都可以交替使用。Foundation 框架的API生成并持有的对象可以用 Core Foundation 框架的API释放,反之亦然。
因为 Core Foundation 对象与 Objective-C 对象没有区别,所以在 MRC 时,只用简单的C语言的转换也能实现互换。这种转换不需要使用额外的CPU资源,因此也被成为“免费桥”(Toll-Free Bridge)。
__bridge:只做类型转换,不修改相关对象的引用计数。
例:
CFMutableArrayRef cfArray = NULL;
{
/*
* 变量 obj 生成并持有对象的强引用
*/
NSMutableArray *obj = [[NSMutableArray alloc] init];
/*
* 因为 __bridge 转换不改变对象的持有状态,cfArray 不持有对象的强引用
*/
cfArray = (__bridge CFMutableArrayRef)obj;
printf("retain count = %ld\n",CFGetRetainCount(cfArray));
}
/*
* 因为 变量obj 超出作用域,对象得到释放
* 再次访问对象出错!(悬垂指针)
*/
printf("retain count after the scope = %ld\n",CFGetRetainCount(cfArray));
控制台:
__bridge_retained(等价于 CFBridgingRetain):类型转换后,将相关对象的引用计数加1。
例:
CFMutableArrayRef cfArray = NULL;
{
/*
* 变量 obj 生成并持有对象的强引用
*/
NSMutableArray *obj = [[NSMutableArray alloc] init];
/*
* 通过 __bridge_retained 将对象CFRetain赋值给 cfArray,引用计数+1
*/
cfArray = (__bridge_retained CFMutableArrayRef)obj;
// cfArray = CFBridgingRetain(obj); 作用同上
printf("retain count = %ld\n",CFGetRetainCount(cfArray));
}
/*
* 因为 变量obj 超出作用域,对其强引用失效,引用计数-1
*/
printf("retain count after the scope = %ld\n",CFGetRetainCount(cfArray));
/*
* 不再使用对象时,将其释放掉
*/
CFRelease(cfArray);
控制台:
__bridge_transfer(等价于 CFBridgingRelease):类型转换后,将该对象的引用计数交给ARC管理,Core Foundation 对象在不用时,不需要调用 CFRelease 方法。
例:
NSMutableArray *obj = NULL;
{
/*
* 变量 cfArray 生成并持有对象的强引用,引用计数为“1”
*/
CFMutableArrayRef cfArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
printf("retain count = %ld\n",CFGetRetainCount(cfArray));
/*
* 通过 __bridge_transfer 赋值,
* 变量 obj 持有对象强引用,cfArray不再持有对象的强引用,引用计数不变,为“1”
*/
obj = (__bridge_transfer NSMutableArray *)cfArray;
// obj = CFBridgingRelease(cfArray); 作用同上
/*
* 经由 __bridge_transfer 转换后,
* 赋值给变量 cfArray 中的指针也指向仍然存在的对象(只是不再持有对象的强引用),所以可以正常使用
*/
printf("retain count after the cast= %ld\n",CFGetRetainCount(cfArray));
}
/*
* 因为 变量obj 持有对象的强引用,
* 即使超出 变量cfArray 的作用域,仍然可以正常使用
*/
NSLog(@"class = %p",obj);
控制台:
虽然 Objective-C 和C语言的桥接转换编译器会有智能提示,但是知道其所有权原理对于我们写出高质量的代码还是很有必要的。
千里之行,始于足下~