ARC 和 非ARC 下 oc 对象 和 CF 对象的转换

本文介绍了在ARC和非ARC环境下,Objective-C对象和Core Foundation对象之间的转换方法,包括宏定义CFBridgingRetain和CFBridgingRelease,以及转换符__bridge、__bridge_transfer和__bridge_retained的使用。强调了转换过程中对象所有权的变化,以及避免内存泄漏和野指针的关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在OC和FC之间进行转化的时候,主要是对象的归属问题。共有两种方式:

1、使用宏,可以标识归属者从OC到CF,还是从CF到OC。
NS_INLINE CFTypeRef CFBridgingRetain(id X) { 
    return (__bridge_retain CFTypeRef)X; 
} 
  
NS_INLINE id CFBridgingRelease(CFTypeRef X) { 
    return (__bridge_transfer id)X; 
}

2、使用转化符,如:__bridge,__bridge_transfer,__bridge_retained

__bridge:不涉及对象所有关系改变
__bridge_transfer:给予 ARC 所有权
__bridge_retained:解除 ARC 所有权
id my_id; 
CFStringRef my_cfref; 
 
NSString   *a = (__bridge NSString*)my_cfref;     // Noop cast. 
CFStringRef b = (__bridge CFStringRef)my_id;      // Noop cast. 


NSString   *c = (__bridge_transfer NSString*)my_cfref; // -1 on the CFRef 
CFStringRef d = (__bridge_retained CFStringRef)my_id;  // returned CFRef is +1

非ARC模式下:
#pragma mark – View lifecycle 


- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    NSLog(@"=%@", [self escape:@"LIN986LIN"]); 
} 
-(NSString *)escape:(NSString *)text 
{ 
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)text,NULL,CFSTR("!*’();:@&=+$,/?%#[]"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
}

ARC模式下:
可以看到xcode自动把上面函数转化为: 
#pragma mark – View lifecycle 
- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    NSLog(@"=%@", [self escape:@"wangjun"]); 
} 
-(NSString *)escape:(NSString *)text  
{ 
     return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)text,NULL,CFSTR("!*’();:@&=+$,/?%#[]"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
}
在arc中,CF和OC之间的转化桥梁是 __bridge,有两种方式:
__bridge_transfer  ARC接管管理内存
__bridge_retained  ARC释放内存管理
oc 到 CF 的转化,需要把OC的内存管理权释放掉。
NSString *str = [[NSString alloc] initWithFormat:@"Welcome 	, %@!", name]; 
CFStringRef strref = (__bridge_retained CFStringRef)str; 
// do something with strref  
CFRelease(strref);
最后由CF进行内存释放。
上面代码等同于:
CFStringRef strref = CFBridgingRetain(str); 
// do something with strref    
CFRelease(strref);
CF转化为OC时,并且对象的所有者发生改变,则使用CFBridgingRelease()或__bridge_transfer 。
OC转化为CF时,并且对象的所有者发生改变,则使用CFBridgingRetain()或__bridge_retained
当一个类型转化到另一种类型时,但是对象所有者没有发生改变,则使用__bridge.
CF对象和OC对象混用可能出现的问题:
ARC模式下,自动回收只针对Objective-C对象有效,对于Core Foundation对象还是需要我们手动进行释放的,CFRelease().
分析下面的情况:
在一个方法里定义了一个CGColorRef对象:CGColorRef cf
分别通过以下三种方式给cf赋值后,再使用cf时会有什么不同呢?
方式一:
UIColor* color = [[UIColor alloc] initWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f];
cf = color.CGColor;
方式二:
cf = [[UIColor alloc] initWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f].CGColor;
方式三:
cf = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f].CGColor;
方式一和方式三运行没问题。方式二后再使用cf会crash,因为这时cf已经是野指针了。
分析如下:
方式一中,color对象默认是strong强引用,在这个方法的生命周期内都有效,在退出这个方法时才会被自动释放池释放。所以用它的CGColor是没有问题的。
方式三中类似,colorWithRed:…这是个类方法,会返回一个autorelease对象,对象在自动释放池释放之前都有效,所以也不会出问题。
方式二中,生成的UIColor对象没有给任何owner,相当于一个weak弱引用,alloc之后被马上释放了,所以他的CGColor变量也随之成了野指针。
ARC下OC对象与CF对象桥接:
下面一行代码:
CFStringRef s1 = (CFStringRef)[[NSString alloc] initWithFormat:@”Hello, %d!”, 1];
在ARC下面会报编译问题,并会给出推荐的解决方案:
CFStringRef s1 = (__bridge CFStringRef)[[NSString alloc] initWithFormat:@”Hello, %d!”, 1];
这里NSString生成的是OC的对象,内存由ARC负责。s1是CF的对象,内存还是需要自己手动管理。两个变量转换时需要添加桥接标识。
上面这种情况下不会crash,也不会有内存泄露。因为alloc出来的内存会被ARC回收,这块内存的所有关系没变。
如果后面加上CFRelease(s1);就会crash,因为这块内存还是归ARC管的,这样会过度释放。
修改一下:
CFStringRef s1 = (__bridge_retained CFStringRef)[[NSString alloc] initWithFormat:@”Hello, %d!”, 1];
这种情况下,对象的所有权交给CF对象了。就需要加上CFRelease(s1);进行释放,否则会产生泄露。
再看下面代码:
CFUUIDRef uu = CFUUIDCreate(NULL);
CFStringRef s2 = CFUUIDCreateString(NULL, uu);
CFRelease(uu);


NSString* str = (__bridge NSString*)s2;
NSLog(@”STR:%@”,str);
CFRelease(s2);
这里的uu和s2都需要使用CFRelease释放,因为他们不是OC对象,并且是create出来的内存,并且所有权没有被释放。
如果改动下面一行代码:
NSString* str = (__bridge_transfer NSString*)s2;
这时候运行程序会引起crash,因为s2的所有权已经交给ARC中的str了,ARC会负责释放这块内存。
这时候调用CFRelease(s2);会造成过度释放。所以应该把这么行代给去了。
注:
ARC模式下,自动回收只针对Objective-C对象有效,对于使用create,copy,retain等生成的Core Foundation对象还是需要我们手动进行释放的,CFRelease().



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值