目录
返回目录
首先在ARC环境下,如果不需要专门索要对象所有权,可以直接使用__bridge + 类型来执行Toll-Free Bridging,因此转换后的对象也不需要进行释放。
比如下段代码,不需要专门释放CFStringRef,ARC会释放NSString。他们指向同一个内存数据。
//ARC会释放str
NSString *str = [[NSString alloc] initWithCString:"mgen" encoding:NSUTF8StringEncoding];
CFStringRef strRef = (__bridge CFStringRef)str;
CFShow(strRef);
还有相反方向的,同样,这里ARC不会释放转换后的NSString,原创建方(CFStringRef)有责任去释放对象数据。
//创建的CFStringRef需要释放
CFStringRef strRef = CFStringCreateWithCString(kCFAllocatorDefault, "mgen", kCFStringEncodingASCII);
NSString *str = (__bridge NSString*)strRef;
NSLog(@"%@", str);
CFRelease(strRef);
如果需要索要对象所有权,对于Foundation到Core Foundation对象的转换,可以使用__bridge_ratained或者CFBridgingRetain函数。
这样转换后,相当于对源对象进行一次retain,因此转换后的Core Foundation对象需手动进行释放。
如下代码:
//输出CFStringRef的retain count
void printStrRefRetainCount(CFStringRef ref)
{
NSLog(@"%ld", CFGetRetainCount(ref));
}
//通过__bridge_retained获取从NSString转换retain后的CFStringRef
CFStringRef getCFStringRef()
{
NSString *str = [[NSString alloc] initWithCString:"mgen" encoding:NSUTF8StringEncoding];
//返回retained后的CFStringRef
CFStringRef strRef = (__bridge_retained CFStringRef)str;
return strRef;
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
CFStringRef strRef = getCFStringRef();
printStrRefRetainCount(strRef);
//这里可以使用strRef
//释放
CFRelease(strRef);
}
return 0;
}
而对于Core Foundation到Foundation对象的转换,可以使用__bridge_transfer或者CFBridgingRelease函数。转换后的Foundation对象会由ARC来处理。
如下代码:
//输出CFStringRef的retain count
void printStrRefRetainCount(CFStringRef ref)
{
NSLog(@"%ld", CFGetRetainCount(ref));
}
//输出NSString的retain count
void printStrRetainCount(NSString *str)
{
CFStringRef strRef = (__bridge CFStringRef)str;
NSLog(@"%ld", CFGetRetainCount(strRef));
}
//通过__bridge_transfer获取NSString
NSString* getNSString()
{
CFStringRef strRef = CFStringCreateWithCString(kCFAllocatorDefault, "mgen", kCFStringEncodingUTF8);
printStrRefRetainCount(strRef);
//移交给ARC处理的NSString
NSString *str = (__bridge_transfer NSString*)strRef;
printStrRetainCount(str);
return str;
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *str = getNSString();
printStrRetainCount(str);
}
return 0;
}
注意这段代码会输出:
1
2
3
这是由于ARC会在赋值后对变量进行retain。而我们解释的是创建后的CFStringRef不需要进行CFRelease,ARC会自动管理NSString的内存释放。可以通过Xcode中的Product – Analyze来分析代码,不会有任何内存泄露提示的。
当然,我们也可以这样做:
NSString *str1 = [[NSString alloc] initWithCString:"mgen" encoding:NSUTF8StringEncoding];
CFStringRef ref1 = (__bridge_retained CFStringRef)str1;
NSString *str2 = (__bridge_transfer NSString*)ref1;
NSLog(@"%@", str2);
哈哈,代码会先在Foundation世界中创建一个NSString,然后把它转换到Core Foundation世界中,最后再转换回来。ARC会最终管理内存释放的。
返回目录
非ARC环境下很好理解。既然是Toll-Free Bridging,两者可以直接互转,两者指向的也是同一块内存区域。所以Foundation和Core Foundation下的手动内存管理方式是通用的。
如下代码:
void printRetainCount(id obj)
{
NSLog(@"%lu", (unsigned long)[obj retainCount]);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *str = [[NSString alloc] initWithFormat:@"mgen"];
printRetainCount(str);
CFStringRef strRef = (CFStringRef)str;
CFRetain(strRef);
printRetainCount(str);
[str retain];
NSLog(@"%ld", (long)CFGetRetainCount(strRef));
NSLog(@"Releasing");
CFRelease(strRef);
printRetainCount(str);
CFRelease(strRef);
printRetainCount(str);
CFRelease(strRef);
}
return 0;
}
输出:
1
2
3
Releasing
2
1