- 理解__bridge,__bridge_transfer和__b
- __bridge,__bridge_retained,__bri
- __bridge , __bridge_transfer, __
- _ _bridge,_ _bridge_retained 和 _
- Objective-C ARC 下 OC 对象和 CF 对象之间
- iOS-浅谈__bridge
- __bridge_retained 与 __bridge_tra
- __bridge、__bridge_retained和 __br
- #__bridge,__bridge_retained和__br
- __bridge、__bridge_retained和 __br
前言
昨天使用Core Graphics写个一个有趣的涂鸦板,自然而然的就想到了Core Foundation这个框架,现在就来谈谈它的使用。
作为Cocoa众多框架中最重要最基本的两个框架:“Foundation”和“UIKit”。Foundation是框架的基础,和界面无关,提供NSArray,NSDictionary这类的数据结构,其中包含了大量常用的API;UIKit是基础的UI类库,提供诸如UIView这类的控件,我们在iOS开发中经常用到。但是有的时候需要底层框架,底层框架名字通常以Core开头,比如Core Text,Core Graphics和Core Video.它们都是以Core Foundation为基础的C语言的API。
那么问题来了
Core Foundation 框架 (CoreFoundation.framework) 是一组C语言接口,而不是Objective-C的,而CF框架和 Foundatio n框架紧密相关,它们为相同功能提供接口,但 Foundation 框架提供Objective-C接口,如果将 Foundation 对象和CF类型对象互相转换使用,那在内存管理这就比较蛋疼了。在ARC环境下,ARC可以管理Objective-C对象的内存处理, 但是对CF对象却无能为力,如果是MRC环境下,全部都是手动管理内存,这就没有什么问题了,但是,你还在MRC的环境下开发吗?别担心,苹果爸爸还是不会坑自己人的,肯定会给你相应的解决方法。
解决方案
如果想要两种对象相互转换,可以利用两个框架之间的 “toll-free bridging”。所谓的Toll-free bridging是说您可以在某个框架的方法或函数同时使用 Core Foundation 和 Foundation 框架中的某些类型。很多数据类型支持这一特性,其中包括群体和字符串数据类型。每个框架的类和类型描述都会对某个对象是否为 toll-free bridged,应和什么对象桥接进行说明。
对此,苹果爸爸一共提供了3种方法:
- _ _bridge
- _ _bridge_retained == CFBridgingRetain()
- _ _bridge_transfer == CFBridgingRelease()
- _ _bridge只做类型转换,不改变对象所有权,也是最常用的转换符,它也包括两个不同的方式。
1.从OC对象转换到CF对象,那么这个对象还是由ARC来管理内存,不用手动释放内存:
//例:
- (void)bridgeOCToCF
{
NSString * nsstr = [[NSString alloc]initWithFormat:@"CJProgrammer"];
CFStringRef cfstr = (__bridge CFStringRef)nsstr;
//告诉编译器,这个变量我(假装)使用了,不要提示变量未使用的警告。
(void)cfstr;
}
2.从CF对象转换到OC对象,那么这个对象就需要手动释放:
//例:
- (void)bridgeCFToOC
{
CFStringRef cfstr = CFStringCreateWithCString(NULL, "CJProgrammer", kCFStringEncodingASCII);
NSString * nsstr = (__bridge NSString *)cfstr;
(void)nsstr;
CFRelease(cfstr);
}
- _ _bridge_retained和CFBridgingRetain()将OC对象转换为CF对象,把对象所有权转移给CF对象,ARC就不能再管理这个对象的内存,需要使用CFRelease或者相关方法手动来释放内存。
//例:
- (void)bridge_retained
{
NSString * nsstr = [[NSString alloc]initWithFormat:@"CJProgrammer"];
CFStringRef cfstr = (__bridge_retained CFStringRef)nsstr;
(void)cfstr;
CFRelease(cfstr);
}
CFBridgingRetain()是_ _bridge_retained的宏方法,使用起来是和__bridge_retained等价的,查看CFBridgingRetain(),注释写的很清楚:
// After using a CFBridgingRetain on an NSObject, the caller must take responsibility for calling CFRelease at an appropriate time.
NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) {
return (__bridge_retained CFTypeRef)X;
}
下面的两种写法是完全等价的:
CFStringRef cfstr = (CFStringRef)CFBridgingRetain(nsstr);
CFStringRef cfstr = (__bridge_retained CFStringRef)nsstr;
- _ _bridge_transfer和CFBridgingRelease()将CF对象转换为OC对象,把对象所有权转移给OC对象,所以ARC就可以对这个对象进行管理,就不用再手动管理内存了。
- (void)bridge_transfer
{
CFStringRef cfstr = CFStringCreateWithCString(NULL, "CJProgrammer", kCFStringEncodingASCII);
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
NSString * nsstr = (NSString *)CFBridgingRelease(cfstr);
(void)nsstr;
}
CFBridgingRelease()是_ _bridge_transfer的宏方法,使用起来是和__bridge_transfer等价的,查看CFBridgingRelease(),可以看到它的定义方式:
NS_INLINE id _Nullable CFBridgingRelease(CFTypeRef CF_CONSUMED _Nullable X) {
return (__bridge_transfer id)X;
}
下面的两种写法也是完全等价的:
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
NSString * nsstr = (NSString *)CFBridgingRelease(cfstr);
总结
看了这么多,我对上面的内容做了一下简要的总结:
- _ _bridge:最开始创建的是OC对象,无论怎么使用__bridge转换,都是在ARC的管理下,不用手动释放内存;最开始创建的是CF对象,无论怎么使用_bridge转换,都不会在ARC的管理下,需要手动释放内存;
- _ _bridge_retained和CFBridgingRetain()是将OC对象转换为CF对象,把对象所有权转移给CF对象,ARC就不能再管理这个对象的内存,需要使用CFRelease或者相关方法手动来释放内存;
- _ _bridge_transfer和CFBridgingRelease()是将CF对象转换为OC对象,把对象所有权转移给OC对象,所以ARC就可以对这个对象进行管理,就不用再手动管理内存了。
看到这,你应该已经清楚了CF对象和OC对象相互转换的技巧了,如果还想深入了解,可以看一下Core Foundation的官方文档。
网友评论