移动开发技术

Jason's Blog

__bridge __bridge retained __bridge transfer的区别

iOS开发中,经常会接触到两种对象,Objective-C对象和Core Foundation对象,他们之间有所不同,可以互相转换。最大的不同之处在于,在ARC模式下,前者不用开发者手动管理内存,后者需要开发者手动管理内存,即调用CFRelease方法释放对象,否则会造成内存泄漏。转换的话主要会用到以下3个方法:

  • __bridge,
  • __bridge_retained
  • __bridge_transfer

__bridge可以用于OC对象和CF对象互转,例如

1
2
3
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对象,因为OC对象的默认修饰符是__strong,引用计数会+1,即以下两种写法是一样的。

1
2
NSObject *obj1 = (__bridge id)cfObj1;
NSObject __strong *obj1 = (__bridge id)cfObj1;

__bridge_retained用于OC对象转换为CF对象,例如

1
2
3
4
5
6
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对象,例如

1
2
3
4
5
6
7
8
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

最后来做个练习,看下以下代码输出什么

1
2
3
4
5
6
7
8
9
10
11
12
13
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

答案是

1
2
obj retainCount 4
str retainCount 9223372036854775807

str特殊一点,会被当做是字符串常量,retainCount是一个最大值,保证不会被系统回收。

Comments