深入了解Objective-C 和 Core Foundation 对象相互转换(_bridge)
来源:互联网 发布:js 触发div事件 编辑:程序博客网 时间:2024/06/07 12:48
介绍Core Foundation框架
Core Foundation
是使用C
实现的,它们为iOS应用程序提供基本数据管理和服务功能;
下面列举该框架支持进行管理的数据以及可提供的服务:
1、群体数据类型 (数组、集合等)
2、程序包
3、字符串管理
4、日期和时间管理
5、原始数据块管理
6、偏好管理
7、URL及数据流操作
8、线程和RunLoop
9、端口和soket通讯
特别注意的是:
针对内存管理问题,ARC
可以帮忙管理 Objective-C
对象, 但是不支持Core Foundation
对象的管理,所以转换后要注意一个问题:谁来释放使用后的对象。
二者之间联系
他们虽然属于不同的 Framework,但是具有相同的对象结构,所以可以用标准C的类型转换。
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环境下的,创建一个非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环境下的转换
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
1、__bridge
__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
关键字修饰的变量是一样的。
特别主要的是,被代入对象的所有者需要明确对象生命周期的管理,不要出现异常访问的问题。
1.1、从OC转CF,ARC管理内存
- (void)forExample{ NSString *aNNstring = [NSString stringWithFormat:@"%@",@"hello world"]; CFStringRef aCFString = (__bridge CFStringRef)aNNstring; NSLog(@"Retain count is %ld", CFGetRetainCount(aCFString));}
我们使用Analyze搞一下,没问题,说明确实是ARC来管理内存的。
1.2、 从CF转OC,需要开发者手动释放,不归ARC管
我们看下下面的例子:
- (void)forExample{ CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII); NSString *aNSString = (__bridge NSString *)aCFString; NSLog(@"%@",aNSString); CFRelease(aCFString);}
我们屏蔽掉代码CFRelease(aCFString);
,然后再Analyze搞一下
内存泄露了。还是需要我们乖乖的手动进行内存管理的。
2、 __bridge_retained 或者 CFBridgingRetain()
__bridge_retained
或者CFBridgingRetain()
将Objective-C
对象转换为Core Foundation
对象,把对象所有权桥接给Core Foundation
对象,同时剥夺ARC的管理权,后续需要开发者使用CFRelease
或者相关方法手动来释放对象。
例子1:对象指针角度
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
仍然指向一个有效的实体。说明他拥有该对象的所有权,该对象没有因为出其定义范围而被销毁。
例子2:内存管理例子
【泛型例子】
在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);
3、 __bridge_transfer 或者 CFBridgingRelease()
__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(免费的桥接)
关于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
- 深入了解Objective-C 和 Core Foundation 对象相互转换(_bridge)
- Objective-C 和 Core Foundation 对象相互转换
- Objective-C 和 Core Foundation 对象相互转换内存管理
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C和Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- [ios]Objective-C 和 Core Foundation 对象相互转换的内存管理总结 【转】
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- Objective-C 和 Core Foundation 对象相互转换的内存管理总结
- netty中自定义协议(加码器和解码器)
- Java基础之日期的调取
- golang配置https协议
- 不要暴力,也可以很容易地解题
- C# DATATABLE 重新排序
- 深入了解Objective-C 和 Core Foundation 对象相互转换(_bridge)
- win7/8/10安装好之后再装Centos7,导致无法开机引导的问题解决.md
- js文件中如何使用EL表达式
- Csharp Json解析
- Hyperledger Fabric 之 环境搭建
- Eclipse 一直不停 building workspace... 完美解决总结
- CentOS6/7 使用saltstack源安装saltstack
- hdu 多校联赛 Inversion
- Ubuntu 16.04 LTS 下安装 ibus-rime 输入法