id obj = [[NSObject alloc] init]; void *p = obj;void*对象变回id类型
id obj = p; [obj release];在ARC下
id obj = [[NSObject alloc] init]; void *p = (__bridge void *)obj; id o = (__bridge id)p;
将Objective-C的对象类型用 __bridge 转换为 void* 类型和使用 __unsafe_unretained 关键字修饰的变量是一样的。被代入对象的所有者需要明确对象生命周期的管理,不要出现异常访问的问题。
注意:__bridge:CF和OC对象转化时只涉及对象类型不涉及对象所有权的转化
NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"]; CFURLRef ref = (CFURLRef)url;上面的这段代码在ARC环境下系统会给出错误提示和错误修正,修正后如下:
NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"]; CFURLRef ref = (__bridge CFURLRef)url;系统为我们自动添加了__bridge,因为是OC创建的对象并且在转换时没有涉及对象所有权的转换,所以上面的代码不需要加CFRelease 2>__bridge_retained
id obj = [[NSObject alloc] init]; void *p = (__bridge_retained void *)obj;从名字上我们应该能理解其意义:类型被转换时,其对象的所有权也将被变换后变量所持有。
id obj = [[NSObject alloc] init]; void *p = obj; [(id)p retain];可以用一个实际的例子验证,对象所有权是否被持有。
void *p = 0;{ id obj = [[NSObject alloc] init]; p = (__bridge_retained void *)obj; } NSLog(@"class=%@", [(__bridge id)p class]);
出了大括号的范围后,p 仍然指向一个有效的实体。说明他拥有该对象的所有权,该对象没有因为出其定义范围而被销毁。
注意: __bridge_retained:(与__bridge_transfer相反)常用在将OC对象转换成CF对象时,将OC对象的所有权交给CF对象来管理;(作用同CFBridgingRetain())
NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"]; CFURLRef ref = (__bridge_retained CFURLRef)url; CFRelease(ref);当使用_bridge_retained标识符以后,代表OC要将对象所有权交给CF对象自己来管理,所以我们要在ref使用完成以后用CFRelease将其手动释放.
CFStringRef cfString= CFURLCreateStringByAddingPercentEscapes( NULL, (__bridge CFStringRef)text, NULL, CFSTR("!*’();:@&=+$,/?%#[]"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)); NSString *ocString = (__bridge_transfer CFStringRef)cfString;此时OC即获得了对象的所有权,ARC负责自动释放该对象,如果我们在结尾加上CFRelease(cfString)纯属画蛇添足,虽不会崩溃,但是控制台会打印出该对象被free了两次。
id obj = (id)p; [obj retain]; [(id)p release];那么ARC有效后,我们可以用下面的代码来替换:
id obj = (__bridge_transfer id)p;可以看出来,__bridge_retained 是编译器替我们做了 retain 操作,而 __bridge_transfer 是替我们做了 release1。
NSString *string = [NSString stringWithFormat:...]; CFStringRef cfString = (CFStringRef)string;同样,Core Foundation类型向Objective-C类型转换时,也是简单地用标准C的类型转换即可。
NSString *string = [NSString stringWithFormat:...]; CFStringRef cfString = (__bridge CFStringRef)string;只是单纯地执行了类型转换,没有进行所有权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。
NSString *string = [NSString stringWithFormat:...]; CFStringRef cfString = (__bridge_retained CFStringRef)string; ...CFRelease(cfString); // 由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release
CFTypeRef CFBridgingRetain(id X) { return (__bridge_retained CFTypeRef)X; } id CFBridgingRelease(CFTypeRef X) { return (__bridge_transfer id)X; }所以,可以用 CFBridgingRetain 替代 __bridge_retained 关键字:
NSString *string = [NSString stringWithFormat:...]; CFStringRef cfString = CFBridgingRetain(string); ... CFRelease(cfString); // 由于Core Foundation不在ARC管理范围内,所以需要主动release。 __bridge_transfer所有权被转移的同时,被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会经常用到 __bridge_transfer 关键字。
CFStringRef cfString = CFStringCreate...(); NSString *string = (__bridge_transfer NSString *)cfString;// CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权,所以不需要调用 release
CFStringRef cfString = CFStringCreate...(); NSString *string = CFBridgingRelease(cfString);五,总结