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语言的桥接转换编译器会有智能提示,但是知道其所有权原理对于我们写出高质量的代码还是很有必要的。

千里之行,始于足下~

上一篇下一篇

猜你喜欢

热点阅读