(1)Foundation与Core Foundation对象
Foundation对象就是使用Object-C创建出来的对象(一般以NS开头), Core Foundation对象主要是使用C语言创建的对象(一般以CF开头),两个框架创建的对象都使用引用计数管理内存。在MRC环境下,Core Foundation框架中的retain/release分别是CFRetain/CFRelease。Core Foundation 与 Foundation 框架创建出来的对象区别很小,可以在不同的框架中使用,Foundation框架的API生成并持有的对象可以用Core Foundation框架的API释放,反过来也可以。
因为Core Foundation对象与Foundation对象没有区别,转换不需要额外的CPU资源,因此也被称为“免桥接”Toll - Free - Bridge。
(2)显示转换id 和 void*
/* MRC环境下 转换*/
id obj = [[NSObject alloc] init];
void *p = obj;
id o = p;
[o release];
/*ARC环境下 转换*/
在ARC环境下上面代码会引起编译错误,(个人猜测MRC下Foundation与Core Foundation对象都需要手动管理,而ARC环境下Foundation对象内存不需要手动管理Core Foundation对象需要,所以不能直接转需要桥接)
id obj = [[NSObject alloc] init];
void *p = (__bridge void *)obj;
id o = (__bridge id)p;
但是__bridge并不转让对象所有者,其安全性和__unsafe_unretained修饰符相近,甚至更低,如果不注意对象持有者会引起悬垂指针。桥接转换还有另外两种方式,分别是__bridge_retained和__bridge_transfer转换
__bridge_retained转换可使要转换赋值的变量也持有所赋值的对象。在MRC下其源代码是:
id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];
ARC环境下可以写成:
void *p = 0;
{
id obj = [[NSObject alloc] init];
p = (__bridge_retained void *)obj;
}
NSLog(@“class = %@“, [(__bridge id) p]);
obj变量作用域虽然结束了,但是由于__bridge_retained转换使p处于持有该对象的状态,因此对象不会被释放,用完需要手动释放p。
__briege_transfer转换提供与__bridge_retained相反的动作,被转换的变量所持有的对象在改变量赋值后会随之释放。
id obj = (__bridge_transfer id)p;
/*在MRC下表述为*/
id obj = (id)p
[obj retain];
[(id)p release];
(3)Foundation与Core Foundation对象转换 (终于讲到重点了)
** Foundation ——> Core Foundation
/*MRC环境下*/
CFMutableArrayRef cfobject = NULL;
{
id obj = [[NSMutableArray alloc] init];
[obj retain]
cfObject = (CFMutableArrayRef)obj;
CFRetain(cfobject); //记得持有对象
[obj release];
}
CFShow(cfObject);
CFRelease(cfObject);
/*ARC环境下*/
CFMutableArrayRef cfobject = NULL;
{
id obj = [[NSMutableArray alloc] init];//ARC下obj内存管理修饰符默认为__string,所以obj将持有对象
cfObject = (__bridge_retained CFMutableArrayRef)obj; //cfobject已经持有对象
}
//超出作用域,obj释放,但是cfobject还持有对象,所以对象不会释放(ARC管理Foundation对象不管理Core Foundation对象内存)
CFShow(cfObject);
CFRelease(cfObject);
**Core Foundation ——> Foundation
/*MRC环境下*/
{
CFMutableArrayRef cfObject = CFArrayCreateMutable(KCFAllocatorDefault, 0, NULL);
id obj = (id)cfObject;
[obj retained];
CFRelease(cfobject);
NSLog(@“clase=%@“, obj);
[obj release];//此时对象不再拥有持有者,将被释放
}
/*ARC环境下*/
{
CFMutableArrayRef cfObject = CFArrayCreateMutable(KCFAllocatorDefault, 0, NULL);
id obj = (__bridge_transfer id)cfObject; //对象赋值完成后cfObject不在持有对象引用将被释放,但是obj默认修饰符为__strong,所以obj将持有对象
NSLog(@“clase=%@“, obj);
}
//超出作用域,obj释放,此时对象不再拥有持有者,将被释放。
个人总结下:__bridge_retained是在桥接后让Core Foundation对象变量持有对象,即让对象引用计数+1,__bridge_transfer桥接后让Core Foundation对象变量释放所持有的对象,即让对象引用计数-1。而__bridge除了桥接其他什么操作都不做。在ARC环境下,下面的操作是对等的:
cfObject = (__bridge CFMutableArrayRef)obj + CFRetain(cfObject) 与 cfObject = (__bridge_retained CFMutableArrayRef)obj
obj = (__bridge id)cfObject + CFRelease(cfObject) 与 obj = (__bridge_transfer id)cfObject