不经常开辟会将Foundation对象和Core,它们为iOS应用

2019-09-18 01:24栏目:大奖888官网登录
TAG:

Cocoa Foundation是iOS中的一个重要框架, 我们大量的使用了里面封装好的接口. 但是还有许多我们需要的接口并不包含在Cocoa框架中, 比如RSA算法, MD5算法, SHA1算法, AES加密算法等, Cocoa对象库里并没有相应的实现. 这时候我们可以在Core Foundation框架里面去寻找. 包括NSString类里没有的字符串编码GBK, GB2312, GB18030等, 在Core Foundation里, 都能找到相应的编码. 建立Socket连接, 获得输入流和输出流时, 也需要使用Core Foundation里的CFNetwork Api等等.

引言
Core Foundation框架 (CoreFoundation.framework) 是一组C语言接口,它们为iOS应用程序提供基本数据管理和服务功能。下面列举该框架支持进行管理的数据以及可提供的服务:
1.群体数据类型 (数组、集合等)
2.程序包
3.字符串管理
4.日期和时间管理
5.原始数据块管理
6.偏好管理
7.URL及数据流操作
8.线程和RunLoop
9.端口和soket通讯

分享是每个优秀的程序员所必备的品质


  • 框架是由许多类、方法、函数、文档按照一定的逻辑组织起来的集合,以便使研发程序变得更容易
  • 在OSX下的Mac操作系统中大约有80个框架。

Cocoa Foundation和Core Foundation的一个重要区别是: Cocoa Foundation是面向对象的, Core Foundation是非面向对象的. 这是造成内存管理方式区别的原因. Cocoa Foundation中的对象使用ARC自动管理内存, 而对于Core Foundation中的对象则需要进行手动管理内存, 使用完之后都需要手动Release.

Core Foundation框架和Foundation框架紧密相关,它们为相同功能提供接口,但Foundation框架提供Objective-C接口。如果您将Foundation对象和Core Foundation类型掺杂使用,则可利用两个框架之间的 “toll-free bridging”。所谓的Toll-free bridging是说您可以在某个框架的方法或函数同时使用Core Foundatio和Foundation 框架中的某些类型。很多数据类型支持这一特性,其中包括群体和字符串数据类型。每个框架的类和类型描述都会对某个对象是否为 toll-free bridged,应和什么对象桥接进行说明。

Foundation框架

Foundation框架是日常iOS开发中常用的,它是Cocoa框架(事实上是一个框架的集合)重要的组成部分,也是为所有程序开发奠定基础的框架。

Foundation框架中大约有125个可用的头文件,允许使用一些基本对象(数字和字符串),以及一些对象结合(数组、字典和集合),其他功能包括处理日期和时间、内存管理、处理文件系统、存储(或归档)对象、线程和RunLoop以及处理几何数据结构等。

然后又涉及到另一个问题, 就是Cocoa Foundation和Core Foundation相互转换时内存管理问题. Cocoa Foundation和Core Foundation对象相互转换时我们使用__bridge, __bridge_transfer, __bridge_retained关键字.

Toll-free bridging 是ARC下OC对象和Core Foundation对象之间的桥梁

Core Foundation框架

Core Foundation框架 (CoreFoundation.framework) 是一组C语言接口,它们为iOS应用程序提供基本数据管理和服务功能。

Core Foundation框架和Foundation框架紧密相关,它们为相同功能提供接口,不同的是Foundation框架提供Objective-C接口。而Core Foundation框架提供Objective-C接口。有时候开发会将Foundation对象和Core Foundation类型掺杂使用,这就需要使用桥接。

  • 1.__bridge: Cocoa Foundation和Core Foundation对象转化时只涉及对象类型不涉及对象所有权的转化;
  • 2.__bridge_transfer: Cocoa Foundation对象转换成Core Foundation对象时,将Cocoa Foundation对象的所有权交给Core Foundation对象, 此时ARC就能自动管理该内存;
  • 3.__bridge_retained: (与__bridge_transfer相反)常用在将Cocoa Foundation对象转换成Core Foundation对象时, 将Cocoa Foundation对象的所有权交给Core Foundation对象来管理;

在开发iOS应用程序时我们有时会用到Core Foundation对象,下面简称CF。例如Core Graphics、Core Text,并且我们可能需要将CF对象和OC对象进行相互转化,我们知道,ARC环境下,编译器不会自动管理CF对象的内存,我们需要手动管理。这就是我们在创建一个CF对象以后需要我们使用CFRelease将其手动释放。

桥接
  • 桥接就是在Foundation框架中的对象Core Foundation框架中的变量之间进行类型转换
  • Core FoundationFoundation框架更加底层,是纯C语言的框架
  • Foundation框架在Core Foundation框架的基础上进行封装,增加了面向对象的思想

以字符串为例:
Foundation框架 :NSString *stringOC ;
Core Foundation框架 :CFStringRef stringC ;(不加*)

图片 1

Snip1.png

两个变量stringOCstringC,Foundation框架中有NSString类型,在Core Foundation框架中与之对应的是CFStringRef类型

当使用_bridge_retained标识符以后, 代表Cocoa Foundation要将对象所有权交给Core Foundation对象自己来管理, 所以我们要在各种Ref使用完成以后用Release将其手动释放.

那么CF和OC相互转化的时候该如何管理内存呢?
我们可以通过__bridge,__bridge_transfer,__bridge_retained 来进行内存管理

桥接的几种形式:

1、 __bridge type
__bridge只进行类型转换,不转让对象的所有权

  • stringC = (__bridge CFStringRef)stringOC;
    只是把stringOC所指向对象的地址交给了stringC,原来对象的所有权属于stringOC,转换之后还是属于stringOC,原来是由stringOC管理的内存,现在还是由stringOC管理,在ARC环境下,stringOC可以自动释放

  • stringOC = (__bridge NSString *)stringC;
    只是把stringC所指向变量的地址交给了stringOC,原来变量的所有权属于stringC,转换之后还是属于stringC,原来是由stringC管理的内存,现在还是由stringC管理,需要手动释放,调用CFRelease方法

2、__bridge_retain CF type

  • strC = (__bridge_retain CFStringRef)strOC;
  • Foundation框架的对象转换成Core Foundation框架的变量
  • 同时转让对象的所有权,把对象的所有权从stringOC转移给stringC,原来是由stringOC管理的内存,现在让stringC来管理,需要手动释放,调用CFRelease方法
  • CFBridgingRetain方法和它等价

3、__bridge_transfer Objective-C type

  • stringOC = (__bridge_transfer NSString*)stringC;
    • Core Foundation框架的变量转换成Foundation框架的对象
    • 同时转让变量的所有权,把变量的所有权从stingrC转移给stringOC,原来是由stringC管理的内存,现在让stringOC来管理,在ARC环境下,stringOC可以自动释放
  • CFBridgingRelease方法和它等价

举个栗子, FMDB中的一个大家都知道的一个方法:

1.__bridge
CF和OC对象转化时只涉及对象类型不涉及对象所有权的转化

个人浅见,有误的地方欢迎指正
- inDatabase:(FMDatabase *db))block { /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue * and then check it against self to make sure we're not about to deadlock. */ FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); FMDBRetain; dispatch_sync(_queue, ^() { FMDatabase *db = [self database]; block; if ([db hasOpenResultSets]) { NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); #if defined && DEBUG NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; NSLog(@"query: '%@'", [rs query]); }#endif } }); FMDBRelease;}
//Image I/O 从 NSBundle 读取图片数据
   NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"];
    CGImageSourceRef source = CGImageSourceCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"]], NULL);

MDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 这句代码中使用了__bridge关键字. MDatabaseQueue继承自NSObject, NSObject是Cocoa的根类. 而dispatch_get_specific(const void *key);则返回"the current subsystem-specific context", 因而__bridge在代码中的作用便是把Core Foundation对象转换成Cocoa Foundation对象, 但是由于只涉及对象类型的转换而没有涉及对象控制权的转换, 所有还需要手动的进行Retain和Release. 在代码中体现为:FMDBRetain;``FMDBRelease;

如果上面不添加__bridge ,在ARC环境下,系统会给出错误提示和错误修正,点击错误提示的话,系统会为我们自动添加__bridge ,因为在OC与CF的转化时只涉及到对象类型没有涉及到对象所有权的转化,所以上述代码不需要对CF的对象进行释放,即不需要添加CFRelease

文章有参考网络文章,如有错误,欢迎讨论指出。

注释: iOS ARC 和 非ARC 之间的转换方法  
1,选择项目中的Targets,选中你所要操作的Target,  
2,选Build Phases,在其中Complie Sources中选择需要ARC的文件双击,  
     并在输入框中输入:-fobjc-arc,如果不要ARC则输入:-fno-objc-arc  

为了解决这一问题,我们使用 __bridge 关键字来实现id类型与void*类型的相互转换。

 id obj = [[NSObject alloc] init];
    void *p = (__bridge void *)(obj);
    NSLog(@"obj retainCount %ld",[(id)p retainCount]);

输出结果:

CFDemo[2932:777997] obj retainCount 1

2.__bridge_transfer
常用在CF对象转化成OC对象时,将CF对象的所有权交给OC对象,此时ARC就能自动管理该内存,作用同CFBridgingRelease()

如果非ARC的时候,我们可能需要写下面的代码。

// p 变量原先持有对象的所有权
id obj = (id)p;
[obj retain];
[(id)p release];

那么ARC有效后,我们可以用下面的代码来替换:

// p 变量原先持有对象的所有权
id obj = (__bridge_transfer id)p;

可以看出来,__bridge_retained 是编译器替我们做了 retain 操作,而 __bridge_transfer 是替我们做了 release。

3.__bridge_retained
与__bridge_transfer 相反,常用在将OC对象转化成CF对象,且OC对象的所有权也交给CF对象来管理,即OC对象转化成CF对象时,涉及到对象类型和对象所有权的转化,作用同CFBridgingRetain()

先来看使用 __bridge_retained 关键字的例子程序:

id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)obj;

此时retainCount 会被加1;
从名字上我们应该能理解其意义:类型被转换时,其对象的所有权也将被变换后变量所持有。如果不是ARC代码,类似下面的实现:

id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];

ARC如何获取retainCount

NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)myObject));

来来来举个例子:

       NSString *string = [NSString stringWithFormat:@""];

    CFStringRef cfString = (__bridge CFStringRef)string;

    CFStringRef cfStr = (__bridge_retained CFStringRef)string;

    CFRelease(cfString);// 由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release

    CFRelease(cfStr);

使用 __bridge_retained 可以通过转换目标处(cfStr)的 retain 处理,来使所有权转移。即使 string 变量被释放,cfString变量也变释放,cfStr 还是可以使用具体的对象。只是有一点,由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。

CFStringRef cfString= CFURLCreateStringByAddingPercentEscapes( NULL, (__bridge CFStringRef)text, NULL, CFSTR("!*’();:@&=+$,/?%#[]"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
    NSString *ocString = (__bridge_transfer CFStringRef)cfString;

所有权被转移的同时,被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会经常用到 __bridge_transfer 关键字。

总结:

  1. Core Foundation 对象类型不在 ARC 管理范畴内
  2. Cocoa Framework::Foundation 对象类型(即一般使用到的Objectie-C对象类型)在 ARC 的管理范畴内
    3.__bridge,__bridge_transfer和__bridge_retained 是CF和OC的桥梁
  3. 如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁以及各种对象的生命周期是怎么样的

这是目前在学习ImageIO苹果官方提供的图片解码器,遇到OC和CF之间相互转化的一些问题,重新整理,细致的了解下,以方便后期更加深入的学习。

PS:来简书混,关注是必须的,点赞❤️ 是要给的!

版权声明:本文由大奖888-www.88pt88.com-大奖888官网登录发布于大奖888官网登录,转载请注明出处:不经常开辟会将Foundation对象和Core,它们为iOS应用