ARC之对象转型 __bridge

ARC之对象转型 __bridge,第1张

概述自 Xcode4.2 开始导入ARC机制后,为了支持对象间的转型,Apple又增加了许多转型用的关键字。这一讲我们就来了解其用法,以及产生的理由。 引子 我们先来看一下ARC无效的时候,我们写id类型转void*类型的写法: 12 id obj = [[NSObject alloc] init];void *p = obj; 反过来,当把void*对象变回id类型时,只是简单地如下来写, 1


自 Xcode4.2 开始导入ARC机制后,为了支持对象间的转型,Apple又增加了许多转型用的关键字。这一讲我们就来了解其用法,以及产生的理由。

引子

我们先来看一下ARC无效的时候,我们写ID类型转voID*类型的写法:

12
ID obj = [[NSObject alloc] init];voID *p = obj;

反过来,当把voID*对象变回ID类型时,只是简单地如下来写,

obj = p;[obj release];

但是上面的代码在ARC有效时,就有了下面的错误:

    error: implicit conversion of an Objective-C pointer        to ’voID *’ is disallowed with ARC        voID *p = obj;                  ^    error: implicit conversion of a non-Objective-C pointer        type ’voID *’ to ’ID’ is disallowed with ARC        ID o = p;                ^
__brIDge

为了解决这一问题,我们使用 __brIDge 关键字来实现ID类型与voID*类型的相互转换。看下面的例子。

12345 NSObject alloc] init];p = (__brIDge voID *)obj;o = (__brIDge ID)p;

将Objective-C的对象类型用 __brIDge 转换为 voID* 类型和使用 __unsafe_unretained 关键字修饰的变量是一样的。被代入对象的所有者需要明确对象生命周期的管理,不要出现异常访问的问题。

除过 __brIDge 以外,还有两个 __brIDge 相关的类型转换关键字:

__brIDge_retained __brIDge_transfer

接下来,我们将看看这两个关键字的区别。

__brIDge_retained

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

123 p = (__brIDge_retained voID *)obj;

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

1234 p = obj;[(ID)p retain];

可以用一个实际的例子验证,对象所有权是否被持有。

12345678 p = 0;{ NSObject alloc] init]; p = (__brIDge_retained voID *)obj;}NSLog(@"class=%@",[(__brIDge class]);

出了大括号的范围后,p 仍然指向一个有效的实体。说明他拥有该对象的所有权,该对象没有因为出其定义范围而被销毁。

__brIDge_transfer

相反,当想把本来拥有对象所有权的变量,在类型转换后,让其释放原先所有权的时候,需要使用 __brIDge_transfer 关键字。文字有点绕口,我们还是来看一段代码吧。

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

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

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

obj = (__brIDge_transfer ID)p;

可以看出来,__brIDge_retained 是编译器替我们做了 retain *** 作,而 __brIDge_transfer 是替我们做了 release1

Toll-Free brIDged

在iOS世界,主要有两种对象:Objective-C 对象和 Core Foundation 对象0。Core Foundation 对象主要是有C语言实现的 Core Foundation Framework 的对象,其中也有对象引用计数的概念,只是不是 Cocoa Framework::Foundation Framework 的 retain/release,而是自身的 CFRetain/CFRelease 接口。

这两种对象间可以互相转换和 *** 作,不使用ARC的时候,单纯的用C原因的类型转换,不需要消耗cpu的资源,所以叫做 Toll-Free brIDged。比如 NSArray和CFArrayRef,Nsstring和CFStringRef,他们虽然属于不同的 Framework,但是具有相同的对象结构,所以可以用标准C的类型转换。

比如不使用ARC时,我们用下面的代码:

Nsstring *string = [Nsstring stringWithFormat:...];CFStringRef cfString = (CFStringRef)string;

同样,Core Foundation类型向Objective-C类型转换时,也是简单地用标准C的类型转换即可。

但是在ARC有效的情况下,将出现类似下面的编译错误:

    Cast of Objective-C pointer type ‘Nsstring *’ to C pointer type ‘CFStringRef’ (aka ‘const struct __CFString *’) requires a brIDged cast    Use __brIDge to convert directly (no change in ownership)    Use __brIDge_retained to make an ARC object available as a +1 ‘CFStringRef’ (aka ‘const struct __CFString *’)

错误中已经提示了我们需要怎样做:用 __brIDge 或者 __brIDge_retained 来转型,其差别就是变更对象的所有权。

正因为Objective-C是ARC管理的对象,而Core Foundation不是ARC管理的对象,所以才要特意这样转换,这与ID类型向voID*转换是一个概念。也就是说,当这两种类型(有ARC管理,没有ARC管理)在转换时,需要告诉编译器怎样处理对象的所有权。

上面的例子,使用 __brIDge/__brIDge_retained 后的代码如下:

__brIDge cfString = (__brIDge CFStringRef)string;

只是单纯地执行了类型转换,没有进行所有权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。

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

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

实际上,Core Foundation 内部,为了实现Core Foundation对象类型与Objective-C对象类型的相互转换,提供了下面的函数。

1234567 CFTypeRef CFBrIDgingRetain(ID X) { return (__brIDge_retained CFTypeRef)X;}ID CFBrIDgingrelease(CFTypeRef return (__brIDge_transfer ID)X;}

所以,可以用 CFBrIDgingRetain 替代 __brIDge_retained 关键字:

cfString = CFBrIDgingRetain(string);...CFRelease(cfString); 由于Core Foundation不在ARC管理范围内,所以需要主动release。 __brIDge_transfer

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

cfString = CFStringCreate...();string = (__brIDge_transfer Nsstring *)cfString;CFRelease(cfString); 因为已经用 __brIDge_transfer 转移了对象的所有权,所以不需要调用 release

同样,我们可以使用 CFBrIDgingrelease() 来代替 __brIDge_transfer 关键字。

string = CFBrIDgingrelease(cfString); 总结

由上面的学习我们了解到 ARC 中类型转换的用法,那么我们实际使用中按照怎样的原则或者方法来区分使用呢,下面我总结了几点关键要素。

明确被转换类型是否是 ARC 管理的对象 Core Foundation 对象类型不在 ARC 管理范畴内 Cocoa Framework::Foundation 对象类型(即一般使用到的ObjectIE-C对象类型)在 ARC 的管理范畴内 如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁 各种对象的生命周期是怎样的

1. 声明 ID obj 的时候,其实是缺省的申明了一个 __strong 修饰的变量,所以编译器自动地加入了 retain 的处理,所以说 __brIDge_transfer 关键字只为我们做了 release 处理。

博主:易飞扬 原文链接 : http://www.yifeiyang.net/development-of-the-iphone-simply-6/ @H_533_403@ 总结

以上是内存溢出为你收集整理的ARC之对象转型 __bridge全部内容,希望文章能够帮你解决ARC之对象转型 __bridge所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1053818.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存