Ale*_*dro 31 objective-c automatic-ref-counting
我的一位朋友最近问我关于在ARC下变得活跃的新桥修改器.他问我是否知道在特定时间使用哪些,以及不同的__bridge修饰符之间的区别是什么.他告诉我,"那么它们是如何工作的,我什么时候使用它们,我如何使用它们,以及它们如何在"引擎盖下"工作?
注意:这应该是一个"分享你的知识"类型的问题,我自己回答了这个问题,但我不确定我是否正确设置了它.
Ale*_*dro 60
因为我了解它们是什么以及它们最近是如何运作的,所以我希望与其他任何希望了解ARC下__bridge修饰符的人分享,这可能是混乱的原因,因为过去的免费桥接已经完成用简单的演员.
过去,如果您想将NSArray对象转换为CFArrayRef用于任何目的,可以使用这样的简单转换来完成:
NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects
CFArrayRef arrayRef = (CFArrayRef) myArray;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,也许您有一个NSArray颜色,需要将其转换为CFArrayRef,以便与CoreGraphics一起使用来绘制渐变.
但是使用ARC,这将不再适用于您,您将收到此错误:
那到底是什么意思啊!?!
事实证明,当你做这种演员时,ARC不喜欢它,甚至会给你一些"修复它"的解决方案,它们似乎都有相同的__bridge关键字,所以让我们对它们正确!
在ARC下,我们有3个主要的__bridge修饰符:
__桥
__bridge_retained (由CFBridgingRetain函数合作)
__bridge_transfer (由CFBridgingRelease函数合作)
所以我们将从__bridge开始.它是什么?__bridge只是另一种说法:"嘿编译器,只要给我一个我的darn casted对象!".编译器很乐意这样做并返回给你一个你喜欢的铸造对象!
但是,因为你想要一个"自由"的类似对象,你仍然负责释放最初分配的对象的内存.在这种情况下,如果我这样做:
NSArray* myArray = [NSArray alloc]init];
CFArrayRef arrayRef = (__bridge CFArrayRef) myArray;
Run Code Online (Sandbox Code Playgroud)
我仍然负责释放myArray内存,因为它是最初分配的对象.记住,__ bridge只是告诉编译器执行演员!因为我在ARC下编译,我没有明确地在myArray对象上调用[-release],ARC会为我做!
请注意,__bridge修饰符可以双向工作!(因此,免费桥接)你可以像以下一样轻松地将CF对象强制转换为NS对象(即免费桥接!):
CFArrayRef arrayRef; // allocate this arrayRef and give it a value later on
//... amazing code.....
NSArray* myArray = (__bridge NSArray*)arrayRef;
Run Code Online (Sandbox Code Playgroud)
但由于CF对象将是最初分配的对象,我必须调用CFRelease(无论如何);
现在让我们转到__bridge_retained及其犯罪伙伴CFBridgingRetain().这个__bridge修饰符明确地适用于将NS对象的所有权转移 到CF OBJECT(因此我们将期望手动CFRelease(无论如何),因为它是CF类型对象)
意思是,如果我再次使用旧方案,但这次使用__bridge_retained:
NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects
CFArrayRef arrayRef = (__bridge_retained) myArray;
Run Code Online (Sandbox Code Playgroud)
现在,arrayRef对象具有对myArray指针所拥有的内存的显式所有权.因为现在CF类型拥有所有权,我必须使用CFRelease(无论如何)自行发布;
那么CFBridgingRetain()函数在所有这些混乱中扮演什么角色?它与我们刚刚谈到的演员扮演的角色完全相同!我们来看看CFBridgingRetain的函数原型:
CFTypeRef CFBridgingRetain(id x);
Run Code Online (Sandbox Code Playgroud)
我们可以看到,它几乎只是将整个(__bridge_retained)概念简化为一个函数!在"输入"NS类型对象后,我们正在回收CF对象!基!是的,我知道这太棒了!一次坐着太酷了!是的,它还执行内存"所有权"转移..多么棒!
最后,但绝不是最少,__ bridge_transfer和全能的CFBridgingRelease()!
__bridge_transfer几乎与__bridge_retained相反.__bridge_transfer修饰符将CF对象类型的所有权转移到NS对象类型.
因此,让我们参考整个过程中使用的示例来剖析它:
NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects
CFArrayRef arrayRef = (__bridge_retained) myArray;
// at this point, arrayRef holds the ownership
// Let's add this new line to change things up a bit:
NSArray* otherArray = (__bridge_transfer NSArray*)arrayRef;
Run Code Online (Sandbox Code Playgroud)
那么我们刚写的这个令人敬畏的小程序到底做了什么呢?
第1步:我们分配了一个NSArray
第2步:我们将数组的拥有权传递给arrayRef对象
//在我们继续第3步之前,让我们理解此时arrayRef是所有者
第3步:我们将由ArrayRef拥有的USED所有权重新转移回NSArray*
因为在这一点上,otherArray指针是所有者,所以当我们完成时,说[otherArray release] 似乎很自然,对吧?那么这就是ARC开始的地方,并将为您释放该阵列!
你知道它变凉了吗?这个__bridge修饰符是犯罪中令人敬畏的伙伴:CFBridgingRelease()
使它更酷!CFBridgingRelease有这个函数原型:
id CFBridgingRelease(CFTypeRef x);
Run Code Online (Sandbox Code Playgroud)
我们看到,这与使用__bridge_transfer进行转换时发生的情况完全相同.此功能还将所有权转移到NS对象!这太棒了!
使用CFBridgingXXX函数最初可能会更有意义,因为许多Objective-c程序员仍然具有NARC规则的概念:
所有被召唤的东西:
ñ EW
一个 lloc
[R Etain的
C opy
必须有一个平衡 - 释放电话
这样做:
NSArray* myArray = [[NSArray alloc]init];
// there's the A of NARC!
//(cleaned by ARC)
CFArrayRef arrayRef = CFBridgingRetain(myArray); // there's the R of NARC!!
//NSArray* other = CFBridgingRelease(arrayRef); // cleaned up by ARC
Run Code Online (Sandbox Code Playgroud)
由于保留与发布匹配,可以使学习__bridge的过程变得更容易
如果所有这些仍然可能令人困惑,请以这种方式考虑它:您是指向任何NS对象类型的指针.为了保持一致性,让我们说你是一个NSArray指针,现在它并没有指向任何东西.所以你可以想象你,作为零指针,你站在浴室里关灯.(灯关闭表示你没有指向任何东西).
然后,在代码中,程序员决定将您分配给新的NSArray.即,他/她说:
you = [[NSArray alloc]init];
Run Code Online (Sandbox Code Playgroud)
突然,你站在浴室里的灯已亮了!你指着一个物体!现在在正常的程序执行中,当你完成对象的使用时,你就会释放它.因此,在这种情况下,当您使用完浴室时,请关闭灯.
但不幸的是,你所在的节目并不是很"正常".程序员决定使用一些CoreFoundation对象!的Bleh!
他写了这行代码:
CFArrayRef other = (__bridge_retained CFArrayRef) you;
Run Code Online (Sandbox Code Playgroud)
所以现在发生的是,另一个人在你离开的同时走进浴室.出于礼貌,你不要关灯,因为有另一个人使用洗手间,并负责他/她离开时关灯
在这种情况下,由于洗手间的新所有者是CF对象,程序员必须手动释放它.
但如果他/她写这个怎么办:
CFArrayRef ref = (__bridge CFArrayRef) you;
Run Code Online (Sandbox Code Playgroud)
这里发生的事情就是,另一个人甚至没有问过就像你一样闯进了同一个洗手间!太粗鲁了!最重要的是,他希望你也能跟上他!因此,当 你们两个完成时,作为绅士/女士,你会关灯.
但是,由于你是一个NS类型的对象,ARC来为你清理它:)
最后,如果程序员写这个:
you = (__bridge_transfer NSArray*)arrayRef;
Run Code Online (Sandbox Code Playgroud)
这里发生的事情与第一种情况完全相反.你不是在某人进入的同时离开洗手间,而是在另一个人离开的同时进入洗手间
适用相同的内存管理规则.由于您接管了"拥有"洗手间,您必须手动关闭灯.而且因为你是一个NS类型的对象,ARC会为你做到这一点......再次:)不是ARC这么美!
我知道这可能看起来有点令人生畏和困惑,但是只要按照自己的方式进行操作,再次阅读它,你会发现这个ARC机制有多么令人难以置信!
谢谢大家阅读!希望这有助于:)
感谢@rob mayoff和@ Krishnabhadra提供的所有额外帮助和建议!
归档时间: |
|
查看次数: |
6230 次 |
最近记录: |