__bridge __bridgeretained __bridgetransfer的区别
2013 年 4 月 7 日
iOS开发中,经常会接触到两种对象,Objective-C对象和Core Foundation对象,他们之间有所不同,可以互相转换。最大的不同之处在于,在ARC模式下,前者不用开发者手动管理内存,后者需要开发者手动管理内存,即调用CFRelease方法释放对象,否则会造成内存泄漏。转换的话主要会用到以下3个方法:
- __bridge,
- __bridge_retained
- __bridge_transfer
__bridge可以用于OC对象和CF对象互转,例如
NSObject *obj = [[NSObject alloc] init]; //retain count 1 CFTypeRef cfObj1 = (__bridge CFTypeRef)obj; //retain count 1 NSObject *obj1 = (__bridge id)cfObj1; //retain count 2
在这种转换方式下,如果是OC对象转换成CF对象,引用计数不变,如果是CF对象转换成OC对象,引用计数会+1。
__bridge_retained用于OC对象转换为CF对象,例如
NSObject *obj = [[NSObject alloc] init]; //retain count 1 CFTypeRef cfObj1 = (__bridge_retained CFTypeRef)obj; //retain count 2 //等价写法 NSObject *obj = [[NSObject alloc] init]; //retain count 1 CFTypeRef cfObj1 = (CFTypeRef)CFBridgingRetain(obj); //retain count 2
这种情况下,obj的引用计数会+1,obj的释放不会影响到cfObj1的使用
__bridge_transfer用于CF对象转换为OC对象,例如
NSObject *obj = [[NSObject alloc] init]; //retain count 1 CFTypeRef cfObj1 = (__bridge_retained CFTypeRef)obj; //retain count 2 NSObject *obj1 = (__bridge_transfer id)cfObj1; //retain count 2 //等价写法 NSObject *obj = [[NSObject alloc] init]; //retain count 1 CFTypeRef cfObj1 = (__bridge_retained CFTypeRef)obj; //retain count 2 NSObject *obj1 = (NSObject *)CFBridgingRelease(cfObj1); //retain count 2
最后来做个练习,看下以下代码输出什么
NSObject *obj = [[NSObject alloc] init]; //retain count 1 CFTypeRef cfObj = (__bridge_retained CFTypeRef)obj; //retain count 2 CFTypeRef cfObj1 = (__bridge CFTypeRef)obj; //retain count 2 CFTypeRef cfObj2 = (__bridge_retained CFTypeRef)obj; //retain count 3 NSObject *obj1 = (__bridge_transfer id)cfObj1; //retain count 3 NSObject *obj2 = (__bridge id)cfObj2; //retain count 4 NSLog(@"obj retainCount %ld", (long)CFGetRetainCount(cfObj)); NSString *str = [NSString stringWithFormat:@"testStr"]; CFStringRef cfStr = (__bridge CFStringRef)str; NSLog(@"str retainCount %ld", (long)CFGetRetainCount(cfStr)); //retain count 9223372036854775807 = 0x7FFFFFFFFFFFFFFF
答案是
obj retainCount 4 str retainCount 9223372036854775807
str会被当做是字符串常量,retainCount是一个最大值,保证不会被系统回收。
个人认为苹果的这套API设计得不是很好,比如__bridge,并不是说引用计数不增加,而是看是转换的关系是什么,需要理解记忆一下才行。