Core Foundation
是使用C
实现的,它们为iOS应用程序提供基本数据管理和服务功能;
下面列举该框架支持进行管理的数据以及可提供的服务:
1、群体数据类型 (数组、集合等)
2、程序包
3、字符串管理
4、日期和时间管理
5、原始数据块管理
6、偏好管理
7、URL及数据流操作
8、线程和RunLoop
9、端口和soket通讯
特别注意的是:
针对内存管理问题,ARC
可以帮忙管理 Objective-C
对象, 但是不支持Core Foundation
对象的管理,所以转换后要注意一个问题:谁来释放使用后的对象。
Foundation
对象和 Core Foundation
对象间的转换:俗称桥接 bridge
Core Foundation
框架和Foundation
框架紧密相关,它们为相同功能提供接口,但Foundation
框架提供Objective-C
接口。
如果您将Foundation
对象和Core Foundation
类型掺杂使用,则可利用两个框架之间的 “toll-free bridging”。
所谓的Toll-free bridging是说您可以在某个框架的方法或函数同时使用Core Foundatio
和Foundation
框架中的某些类型。
很多数据类型支持这一特性,其中包括群体和字符串数据类型。
每个框架的类和类型描述都会对某个对象是否为 toll-free bridged,应和什么对象桥接进行说明。
如需进一步信息,请阅读Core Foundation
框架参考。
本项目是ARC环境下的,创建一个非ARC的BridgeMRC
的NSObject
文件。
#import "BridgeMRC.h"
@implementation BridgeMRC
- (void)forExample{
NSString *aNNstring = @"hello world";
CFStringRef aCFString = (CFStringRef)aNNstring;
NSString *aString = (NSString *)aCFString;
NSLog(@"%@",aString);
[aNNstring release];
}
@end
我们会发现,真的只是单纯的转化,地址并没有变。
其实不测试也会是如此,毕竟没有new,只是转化而已。
最后不要忘记这是MRC环境下,要手动release
。
ARC的诞生大大简化了我们针对内存管理的开发工作,但是只支持管理 Objective-C
对象, 不支持 Core Foundation
对象。
Core Foundation
对象必须使用CFRetain
和CFRelease
来进行内存管理。
那么当使用Objective-C
和Core Foundation
对象相互转换的时候,必须让编译器知道,到底由谁来负责释放对象,是否交给ARC处理。只有正确的处理,才能避免内存泄漏和double free导致程序崩溃。
根据不同需求,有3种转换方式: __bridge (不改变对象所有权) __bridge_retained 或者 CFBridgingRetain() (解除 ARC 所有权) __bridge_transfer 或者 CFBridgingRelease() (给予 ARC 所有权)
原文是这么写的: A bridged cast is a C-style cast annotated with one of three keywords: (__bridge T) op casts the operand to the destination type T. If T is a retainable object pointer type, then op must have a non-retainable pointer type. If T is a non-retainable pointer type, then op must have a retainable object pointer type. Otherwise the cast is ill-formed. There is no transfer of ownership, and ARC inserts no retain operations. (__bridge_retained T) op casts the operand, which must have retainable object pointer type, to the destination type, which must be a non-retainable pointer type. ARC retains the value, subject to the usual optimizations on local values, and the recipient is responsible for balancing that +1. (__bridge_transfer T) op casts the operand, which must have non-retainable pointer type, to the destination type, which must be a retainable object pointer type. ARC will release the value at the end of the enclosing full-expression, subject to the usual optimizations on local values. These casts are required in order to transfer objects in and out of ARC control; see the rationale in the section on conversion of retainable object pointers. Using a __bridge_retained or __bridge_transfer cast purely to convince ARC to emit an unbalanced retain or release, respectively, is poor form.
文档传送门:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#bridged-casts
__bridge
只做类型转换,不改变对象所有权,是我们最常用的转换符。
我们通过泛型稍微了解一下,然后通过具体的NSString
类型来详细解谈。
在MRC中,二者可以互相任意的转换使用。
id obj = [[NSObject alloc] init];
void *p = obj;
id obj1= p;
[obj1 release];
在ARC中,需要进行bridge
id obj = [[NSObject alloc] init];
void *p = (__bridge void *)(obj);
id obj1= (__bridge id)(p);
将Objective-C
的对象类型用 __bridge
转换为void*
类型和使用__unsafe_unretained
关键字修饰的变量是一样的。
特别主要的是,被代入对象的所有者需要明确对象生命周期的管理,不要出现异常访问的问题。
- (void)forExample{
NSString *aNNstring = [NSString stringWithFormat:@"%@",@"hello world"];
CFStringRef aCFString = (__bridge CFStringRef)aNNstring;
NSLog(@"Retain count is %ld", CFGetRetainCount(aCFString));
}
我们使用Analyze搞一下,没问题,说明确实是ARC来管理内存的。
我们看下下面的例子:
- (void)forExample{
CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII);
NSString *aNSString = (__bridge NSString *)aCFString;
NSLog(@"%@",aNSString);
CFRelease(aCFString);
}
我们屏蔽掉代码CFRelease(aCFString);
,然后再Analyze搞一下
内存泄露了。还是需要我们乖乖的手动进行内存管理的。
__bridge_retained
或者CFBridgingRetain()
将Objective-C
对象转换为Core Foundation
对象,把对象所有权桥接给Core Foundation
对象,同时剥夺ARC的管理权,后续需要开发者使用CFRelease
或者相关方法手动来释放对象。
void *p = 0;
{
id obj = [[NSObject alloc] init];
p = (__bridge_retained void *)obj;
}
NSLog(@"class=%@", [(__bridge id)p class]);
运行后,我们可以看到结果
2017-08-10 17:14:07.095 1111111111[26587:539032] class=NSObject
出了大括号的范围后,p
仍然指向一个有效的实体。说明他拥有该对象的所有权,该对象没有因为出其定义范围而被销毁。
在MRC环境下,
id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];
在ARC环境下,
id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)(obj);
- (void)forExample{
NSString *aNNstring = [NSString stringWithFormat:@"%@",@"hello world"];
CFStringRef aCFString = (__bridge_retained CFStringRef)aNNstring;
CFRelease(aCFString);
NSLog(@"Retain count is %ld", CFGetRetainCount(aCFString));
}
我们屏蔽掉代码CFRelease(aCFString);
,然后再Analyze搞一下
内存泄露了。还是需要我们乖乖的手动进行内存管理的。
Ps:
CFBridgingRetain()
是__bridge_retained
的宏方法,在Core Foundation
内部,提供了以下函数:
CFTypeRef CFBridgingRetain(id X) {
return (__bridge_retained CFTypeRef)X;
}
下面两行代码等价:
CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString;
CFStringRef aCFString = (CFStringRef) CFBridgingRetain(aNSString);
__bridge_transfer
或者CFBridgingRelease()
将非Objective-C
对象转换为Objective-C
对象,同时将对象的管理权交给ARC,开发者无需手动管理内存。
在MRC下,
id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];
// p 变量原先持有对象的所有权
id obj2 = (id)p;
[obj2 retain];
[(id)p release];
[obj2 release];
[obj release];
在ARC下,
id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)(obj);
id obj2 = (__bridge_transfer id)(p);
说明在MRC环境下,我们是需要手动进行内存管理的。
在ARC环境下,使用__bridge_retained
和__bridge_transfer
相当于自动的进行了retain
release
内存管理操作。
使用__bridge_transfer
,内存管理就交给了ARC进行处理。
- (void)forExample{
NSString *aNNstring = [NSString stringWithFormat:@"%@",@"hello world"];
CFStringRef aCFString = (__bridge_retained CFStringRef)aNNstring;
NSString *bNNstring = (__bridge_transfer NSString *)(aCFString);
NSLog(@"%@",bNNstring);
}
Analyze搞一下,没问题。
CFBridgingRelease()
是__bridge_transfer
的宏方法,在Core Foundation
内部,提供了以下函数:
id CFBridgingRelease(CFTypeRef X) {
return (__bridge_transfer id)X;
}
下面两行代码等价:
aNSString = (__bridge_transfer NSString *)aCFString;
aNSString = (NSString *)CFBridgingRelease(aCFString);
关于Toll-Free Bridged Types:
https://developer.apple.com/library/content/documentation/CoreFoundation/Conceptual/CFDesignConcepts/Articles/tollFreeBridgedTypes.html
在iOS世界,主要有两种对象:objective-c
对象和Core Foundation
对象0。
Core Foundation
对象主要是有c语言实现的 Core Foundation Framework
的对象,其中也有对象引用计数的概念,只是不是使用Cocoa Framework
or Foundation Framework
的 retain/release
,而是自身的 CFRetain/CFRelease
接口。
这两种对象间可以互相转换和操作,不使用ARC的时候,单纯的用C原因的类型转换,不需要消耗CPU的资源,所以叫做 Toll-Free bridged(免费的桥接)。
比如 NSArray
和CFArrayRef
, NSString
和CFStringRef
,他们虽然属于不同的 Framework
,但是具有相同的对象结构,所以可以用标准C的类型转换。
正因为Objective-C是ARC管理的对象,而Core Foundation不是ARC管理的对象,所以才要特意这样转换,这与id
类型向void*
转换是一个概念。也就是说,当这两种类型(有ARC管理,没有ARC管理)在转换时,需要告诉编译器怎样处理对象的所有权。
上面的__bridge_retained
和 __bridge_transfer
以及_bridge
就是做了这个事情。
ARC中的bridge介绍
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#bridged-casts
Objective-C 和 Core Foundation 对象相互转换
http://www.cnblogs.com/caolongs/p/7083846.html
[IOS 开发] __bridge、__bridge_transfer和__bridge_retained详解
http://blog.csdn.net/u010130947/article/details/44493931
Toll-Free Bridged Types
https://developer.apple.com/library/content/documentation/CoreFoundation/Conceptual/CFDesignConcepts/Articles/tollFreeBridgedTypes.html
[iOS]深入理解__bridge - OC对象与C++对象的引用转换
https://yq.aliyun.com/articles/58964
网友问答
http://cocoadventures.org/post/126892893629/understanding-bridged-casts
https://stackoverflow.com/questions/14854521/where-and-how-to-bridge