gpt4 book ai didi

objective-c - ARC __bridge修饰符已神秘化

转载 作者:行者123 更新时间:2023-12-03 08:54:07 25 4
gpt4 key购买 nike

最近,我的一位 friend 问我有关在ARC中活跃的新桥修改器的问题。他问我是否知道在特定时间使用哪些,以及不同的__bridge修饰符之间的区别是什么。他问我,“那么它们如何工作,何时使用它们,如何使用它们,以及它们如何在“幕后”工作?

注意:这应该是“分享您的知识”类型的问题,我自己回答了该问题,但不确定是否设置正确。

最佳答案

因为我最近了解了它们的功能以及它们的工作方式,所以我想与其他任何人分享一下有关ARC下的__bridge修饰符的信息,由于过去免费电话桥接的实现,这可能会引起困惑用一个简单的 Actor 表。

过去,如果您想出于任何目的将NSArray对象强制转换为CFArrayRef,则可以通过以下简单的强制转换来完成:

     NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects

CFArrayRef arrayRef = (CFArrayRef) myArray;

在这种情况下,也许您有一个NSArray颜色,需要将其强制转换为CFArrayRef才能与CoreGraphics一起使用以绘制渐变。

但是,对于ARC,这将不再对您有效,并且您会收到此错误:

那么这到底意味着什么!!!

事实证明,当您进行这种类型的转换时,ARC并不喜欢它,甚至会为您提供一些“修复”解决方案,这些解决方案似乎都具有相同的 __bridge 关键字,所以让我们开始吧。他们!

在ARC下,我们有3个主要的__bridge修饰符:

__bridge

__bridge_retained (与 CFBridgingRetain 函数配合使用)

__bridge_transfer (与 CFBridgingRelease 函数配合使用)

因此,我们将从__bridge开始。它是什么? __bridge只是另一种说法:“嘿,编译器,给我我该死的对象!”。编译器很乐意这样做,并向您返回您喜欢的强制转换对象!

但是,由于您想要这样的“自由”转换对象,所以 YOU 仍然负责释放最初分配的对象的内存。在这种情况下,如果我要这样做:
    NSArray* myArray = [NSArray alloc]init];
CFArrayRef arrayRef = (__bridge CFArrayRef) myArray;

我仍然负责释放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;

但是由于CF对象将是最初分配的对象,因此必须调用CFRelease(whatever);

现在,让我们继续进行 __bridge_retained 及其犯罪合作伙伴 CFBridgingRetain()。此__bridge修饰符专门用于将NS对象的所有权转移到CF对象(因此,由于它是CF类型的对象,因此我们希望手动对其进行CFRelease(无论如何))

意思是,如果我要再次执行旧方案,但是这次使用__bridge_retained:
 NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects

CFArrayRef arrayRef = (__bridge_retained) myArray;

现在,arrayRef对象具有myArray指针曾经拥有的内存的显式所有权。因为现在CF类型拥有所有权,所以我必须自己使用CFRelease(whatever)释放它;

那么,在所有这些困惑中, CFBridgingRetain()函数扮演什么角色?它扮演的角色与我们刚才谈到的 Actor 阵容完全相同!让我们看一下CFBridgingRetain的函数原型(prototype):
    CFTypeRef CFBridgingRetain(id x);

我们可以看到,它几乎只是将整个(__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;

那么,我们刚刚编写的这个很棒的小程序到底有什么用呢?

步骤1:我们分配了NSArray

步骤2:我们将数组的所有权传递给arrayRef对象

//在继续执行第3步之前,让我们了解一下arrayRef是所有者

步骤3:我们将原先要由arrayRef拥有的所有权重新转移回NSArray *

因为在这一点上,otherArray指针是所有者,所以完成后似乎说[otherArray release]是自然的,对吧?好吧,这就是ARC介入的地方,它将为您释放该阵列!

而且您知道它会变凉吗?这个__bridge修改器在犯罪方面的出色合作伙伴:
CFBridgingRelease()

使它变得更酷! CFBridgingRelease具有以下功能原型(prototype):
   id CFBridgingRelease(CFTypeRef x);

我们看到,这与使用__bridge_transfer进行转换时发生的事情完全相同。并且此功能还将所有权转移给NS对象!这真是太棒了!

最初,使用CFBridgingXXX函数可能会更有意义,因为许多Objective-C程序员仍然具有NARC规则的概念:

被调用的所有内容:

N ew

loct

R

C opy

必须具有平衡发布 call

这样做:
     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

由于保留发行版相匹配的事实,可以简化__bridge强制转换的学习过程

如果这一切仍然令人困惑,请这样考虑:您是任何NS对象类型的指针。为了保持一致性,我们假设您是一个NSArray指针,但现在没有指向任何对象。因此,您可以想象一下,作为零指针,您站在关着灯的浴室里。 (指示灯熄灭表示您没有指向任何物体)。

然后,在以后的代码中,程序员决定将您分配给新的NSArray。即,他/她这样说:
      you = [[NSArray alloc]init];

突然,您所站在的浴室的灯打开了!您要指向一个对象!现在,在正常的程序执行中,使用完对象后,就可以释放它。因此,在这种情况下,当您使用完浴室后,便会关闭灯。

但是不幸的是,您所使用的程序不是很“正常”。程序员决定使用一些CoreFoundation对象! !

他编写了以下代码行:
    CFArrayRef other = (__bridge_retained CFArrayRef) you;

因此,现在发生的是,另一个人在您离开的同一时间走进洗手间。出于礼貌,您不关灯,因为有人在洗手间,当他/她离开时负责关灯

在这种情况下,由于洗手间的新所有者是CF对象,因此程序员必须手动释放它。

但是,如果他/她要写这个:
   CFArrayRef ref = (__bridge CFArrayRef) you;

这里发生的是,另一个人甚至不问您就闯进了与您同一个洗手间!真没礼貌!最重要的是,他希望您也能跟着他进行清理!因此,当您作为绅士/女士时,当你们两个都结束时,请关掉灯。

但是,由于您是NS类型的对象,因此ARC会为您清理它:)

最后,如果程序员编写此代码怎么办:
    you = (__bridge_transfer NSArray*)arrayRef;

这里发生的情况与第一种情况完全相反。 而不是您在有人进入的同时离开洗手间,而是一个人进入而另一个人离开

相同的内存管理规则适用。由于您接管了“拥有”洗手间,因此您必须手动关闭灯。而且因为您是NS类型的对象,所以ARC会再次为您做... :) ARC不是那么美!

我知道起初这似乎有些令人生畏和令人困惑,但是只要按照自己的方式进行操作,然后再阅读一遍,您就会发现这种ARC机制的工作原理是多么不可思议!

感谢大家阅读!希望这有帮助:)

感谢@rob mayoff和@ Krishnabhadra的支持
所有额外的帮助和建议!

关于objective-c - ARC __bridge修饰符已神秘化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14207960/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com