CF( CoreFoundation)是一套c语言的api,用于面向Objective-C基础数据和服务的管理和维护。
在开启ARC环境下,处理CF对象和OC对象的转化的三个修饰符包括:__bridge, __bridge_transfer, __bridge_retain
1、为什么需要__bridge?
成功编译的需要。
id obj = [[NSObject alloc] init];
void *pObj = obj;
此时编译会报错:Implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast
同样的:
void *pTr = 0;
id newObj = pTr;
编译也会报错:Implicit conversion of C pointer type 'void *' to Objective-C pointer type 'id' requires a bridged cast
也就是说CF对象和OC对象之间,在ARC环境下转化需要bridged cast
上面的实例,只要这么改编译就可以通过了:
id obj = [[NSObject alloc] init];
void *pObj = (__bridge void *) obj;
void *pTr = 0 ;
id newObj = (__bridge id)pTr;
2、为什么需要__bridge_retain ?
防止出现野指针。
看下这个场景:
void *pTr = 0;
{
id anotherObj = [[ViewController alloc] init];
pTr = (__bridge void *)anotherObj; (#)
}
NSLog(@"pTr points class = %@", [(__bridge id)pTr class]); (*)
编译时没有问题的,但是在运行的时候,(*) 会出现必现崩溃:EXC_BAC_ACCESS
我们知道野指针的出现,是这个指针所引用的内存被释放,而这个指针没有置nil(NULL)导致的。
作为局部对象anotherObj,pTr所引用的anotherObj的空间,在括号结束的时候,anotherObj的生命周期结束,空间就被释放了。而pTr还调用这个被释放的内存,所以引发了野指针崩溃。
解决办法就是在 (#) 使用__bridge_retain ,这样即使是anotherObj的生命周期结束了,由于被pTr持有,retain count不为0,空间会继续保留,这样就不会导致pTr是野指针的情形。也就是说,加了__bridge_retain修饰符以后,编译器进行了retain操作。
void *pTr = 0;
{
id anotherObj = [[ViewController alloc] init];
pTr = (__bridge_retain void *)anotherObj; (#)
}
NSLog(@"pTr points class = %@", [(__bridge id)pTr class]); (*)
3、为什么需要__bridge_transfer ?
完全转移对象的所有权,可以防止可能的内存泄漏。
这种场景发生在CF向OC对象转化的过程中。由于CF对象不受ARC的管理,当CF转成OC对象的时候,OC对象可以由ARC管理,CF对象如果不进行release操作,就会导致内存泄漏。
而在转化过程中,将CF对象声明为__bridge_transfer,那么编译器会在完成转化后,自动将CF对象release一次。