简体   繁体   English

Objective-C:ARC中的块

[英]Objective-C: blocks in ARC

I'm transitioning to ARC (Automatic Reference Counting) and this document was very helpful: Transitioning to ARC Release Notes . 我正在转换到ARC(自动引用计数),这个文档非常有用: 转换到ARC发行说明 It says: 它说:

How do blocks work in ARC? 块如何在ARC中工作?

Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. 在ARC模式下向块传递块时块“正常工作”,例如在返回中。 You don't have to call Block Copy any more. 您不必再调用Block Copy。 You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain. 将堆栈“向下”传递给arrayWithObjects:以及其他执行保留的方法时,仍然需要使用[^ {} copy]。

Can somebody elaborate on this a little bit or give some example? 有人可以详细说明这一点或举一些例子吗? I understood that to mean usually I don't need to do [block copy] anymore even if the block is used outside the declared scope as ARC now will take care of it more smartly, but I still need to copy it when I want to pass the block to functions that would retain it. 我明白这通常意味着我不需要再进行[块复制],即使块在声明范围之外使用,因为ARC现在会更加巧妙地处理它,但我仍然需要在我想要时复制它将块传递给保留它的函数。 Is this correct? 这个对吗?

Actually I've experimented with it a little bit and so far it seems okay even if I pass blocks to arrays without copying, so the question. 实际上我已经尝试了一点点,到目前为止,即使我没有复制将块传递给数组也没关系,所以这个问题。 Thanks! 谢谢!

Let's consider the problem from an MRC (manual reference counting) perspective. 让我们从MRC(手动参考计数)的角度考虑问题。 When you are returning a stack block from a function, it is always the right thing to do to return a copy of it (usually with [[ copy] autorelease] ). 当您从函数返回堆栈块时,返回它的副本(通常使用[[ copy] autorelease]始终是正确的做法 This is because the lifetime of the stack block is that function call, which is ending. 这是因为堆栈块的生命周期是函数调用,它正在结束。 So in order for the returned pointer to point to a valid block after returning, of course you have to return a heap copy. 因此,为了使返回的指针在返回后指向有效的块,当然您必须返回堆副本。

However, what about for passing a block as an argument to a function or method. 但是,将块作为参数传递给函数或方法呢? Should you pass a copy of it? 你应该通过它的副本吗? It's a little more complicated. 这有点复杂。 We know that, if you need to store a block for later use in a place that will outlive the function call (eg in an instance variable or global variable, etc.), you need to store a copy of the block. 我们知道,如果你需要存储一个块供以后在一个比函数调用更长的地方使用(例如在一个实例变量或全局变量等中),你需要存储一个块的副本。 But how do we know when this is true (and if it is true, which function (caller/callee) is responsible for copying it)? 但是我们怎么知道这是真的(如果它是真的,哪个函数(调用者/被调用者)负责复制它)?

Generally, when you pass it to a function or method whose parameter is of block type, then you don't need to copy it, because, as a function that takes a block parameter, that function is responsible for copying it if it needs to store it around for later. 通常,当您将其传递给参数为块类型的函数或方法时,您不需要复制它,因为,作为一个带有块参数的函数,该函数负责在需要时复制它将它存放在以后。

But what about passing a block to a function or method whose parameter is of non-block type (like id )? 但是将块传递给参数为非块类型(如id )的函数或方法呢? Then that function does not know that its argument is a block, and so will only retain the object if it needs to store it for later, not copy it. 然后该函数不知道它的参数是一个块,因此只有在需要存储它以供以后使用时才会保留该对象,而不是复制它。 In this case, if we know that the function or method will store the object around for later (eg with -[NSMutableArray addObject:] ), we should pass a copy of the block. 在这种情况下,如果我们知道函数或方法将存储对象以供以后使用(例如使用-[NSMutableArray addObject:] ),我们应该传递该块的副本。 Should we always pass a copy? 我们应该总是传递副本吗? Not necessarily. 不必要。 If we know the function or method will not store the block for later (eg to just print the object), it is inefficient to make a copy of the block. 如果我们知道函数或方法不会存储块以供以后使用(例如仅打印对象),则制作块的副本是低效的。

In ARC, the compiler tries to do as much as possible for you. 在ARC中,编译器会尝试尽可能多地为您执行操作。 So in the case of returning a stack block ("passing it up"), the compiler knows that returning a copy is always the right thing, so it implicitly does that. 因此,在返回堆栈块(“传递它”)的情况下,编译器知道返回副本总是正确的,所以它隐含地这样做。 That's why you don't need to do it yourself anymore. 这就是为什么你不再需要自己动手了。

However, for passing a block to a method or function ("passing it down"), it is not always possible to automatically determine whether copying is needed or not, and extra copying might be inefficient, so the compiler doesn't do anything automatically; 但是,为了将块传递给方法或函数(“传递它”),并不总是能够自动确定是否需要复制,并且额外的复制可能效率低下,因此编译器不会自动执行任何操作; and you the programmer needs to figure it out. 而程序员需要弄清楚它。

I've noticed that in recent versions of the compiler, ARC copies blocks in a lot more situations that I thought, so perhaps they changed the implementation of ARC to pretty much always copy blocks, in order to err on the side of caution, and they believed that the performance cost is not as important. 我注意到在最近版本的编译器中,ARC会在很多情况下复制块,我想也许,所以他们可能会将ARC的实现改为几乎总是复制块,以便谨慎行事,并且他们认为性能成本并不重要。 So it is possible that it will work now passing a block directly to addObject: without explicitly copying. 因此,它现在可以直接将块传递给addObject:无需显式复制。 But I believe that this was not always the case with ARC, and there is no guarantee in the language for this, or that this behavior will stay in the future. 但我相信ARC的情况并非总是如此,并且语言无法保证这一点,或者此行为将在未来保留。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM