iOS Fundation和CoreFoundation的对象转换
1、对象转换时涉及到内存管理权的问题
背景:Foundation框架和CoreFoundation框架分别是由C语言和OC语言实现的苹果官方库。
就是由于是由不同的语言实现的,在iOS5之后,OC开始支持ARC内存管理。在MRC时代,内存的管理全部要有程序员自己来完成,不涉及内存管理权的移交问题。但是在ARC时代,在Foundation 和 CoreFoundation框架之间的一些对象要相互转换,就必须要考虑内存管理权的问题。两个不同框架生成的对象强制转换时,需要交代清楚到底是让ARC帮我们管理内存还是要我们自己手动管理内存。
苹果提供了3个关键词来解决这一问题,分别是__bridge, __bridge_retain, __bridge_transfer。
2、__bridge关键字
/*
__bridge 关键字,它的含义是不改变对象管理权的所有者,本来由ARC管理的Foundation对象,转换成Core Foundation 对象后依然由ARC管理;本来由开发者手动管理的Core Foundation对象转换为Foundation 对象后继续由开发者手动管理
*/
/*ARC 管理的Foundation对象*/
NSString *s1 = @"111";
/*转换后,依然有ARC 管理内存*/
CFStringRef cfStr = (__bridge CFStringRef)s1;
/*开发者手动管理的 CoreFoundation对象*/
CFStringRef s2 = CFStringCreateWithCString(NULL, "cf create string", kCFStringEncodingASCII);
/*转换后仍然需要开发者手动管理释放*/
NSString *fstring = (__bridge NSString*)s2;
NSLog(@"s1: %@", s1);
NSLog(@"cfStr: %@", cfStr);
NSLog(@"s2: %@", s2);
NSLog(@"fstring: %@", fstring);
如果不做特殊处理s2有内存泄漏的危险:
跑一下代码,做一个内存分析可以发现,Xcode 已经开始抱怨了:
这里是控制台打印:
这里是运行时危险警告:
我们打印下报错地址对应的内容,发现就是 s2:
2、__bridge_transfer关键字
/*
__bridge_transfer用在将Core Foundation对象转换成Foundation对象时,进行对象管理权的移交。即本来需要由开发者手动管理和释放的Core Foundation 对象在转换成Foundation对象后,交由ARC来管理对象的释放。开发者不需要再关注对象内存释放的问题。
*/
/*开发者手动管理的Core Foundation对象*/
CFStringRef cfStr2 = CFStringCreateWithCString(NULL, "cf creat string2", kCFStringEncodingASCII);
/*转换后改由ARC管理对象的释放,不用担心内存的泄漏*/
NSString *str2 = (__bridge_transfer NSString *)cfStr2;
/*等效写法*/
//NSString *str2 = (NSString *)CFBridgingRelease(cfStr2);
3、__bridge_obtain关键字
/*
__bridge_retain 用在将Foundation对象转换成 Core Foundation对象时,进行ARC对象管理权的剥夺。即本来由ARC管理的Foundation对象在转换为Core Foundation对象时,ARC不再继续管理,需要开发者自己手动释放对象所占用的内存,否则会发生内存泄漏。
*/
/*ARC管理的Foundatioin对象*/
NSString *s3 = @"string3";
/*转换后ARC不再继续管理,需要手动释放*/
CFStringRef cfString3 = (__bridge_retained CFStringRef)s3;
//另一种写法
//CFStringRef cfString4 = (CFStringRef)CFBridgingRetain(s3);