I've recently come across an Apple document that shows the following property declaration for a block:
我最近遇到了一个Apple文档,它显示了一个块的以下属性声明:
@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end
Also, this article states:
此外,本文还指出:
Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior. For more information, see Blocks Programming Topics.
注意:您应该将copy指定为属性属性,因为需要复制块以跟踪其在原始范围之外的捕获状态。这不是您在使用自动引用计数时需要担心的事情,因为它会自动发生,但是属性属性的最佳实践是显示结果行为。有关更多信息,请参阅块编程主题。
I also read the suggested Blocks Programming Topics but haven't found anything relevant there.
我还阅读了建议的块编程主题,但没有找到任何相关的东西。
I'm still curious as to why defining a block property as "copy" is best practice. If you have a good answer, please try to distinguish between ARC and MRC differences if there are any.
我仍然很好奇为什么将块属性定义为“复制”是最佳实践。如果您有一个好的答案,请尝试区分ARC和MRC差异(如果有)。
Thank you
谢谢
3 个解决方案
#1
23
By default blocks are created on the stack. Meaning they only exist in the scope they have been created in.
默认情况下,会在堆栈上创建块。这意味着它们只存在于已创建的范围内。
In case you want to access them later they have to be copied to the heap by sending a copy
message to the block object. ARC will do this for you as soon as it detects a block needs to be accessed outside the scope its created in. As a best practise you declare any block property as copy because that's the way it should be under automatic memory management.
如果您想稍后访问它们,则必须通过向块对象发送复制消息将它们复制到堆中。一旦检测到需要在其创建的作用域之外访问块,ARC将立即为您执行此操作。作为最佳实践,您将任何块属性声明为副本,因为这是它应该在自动内存管理下的方式。
Read Stack and Heap Objects in Objective-C by Mike Ash for more info on stack vs. heap.
有关堆栈与堆的更多信息,请阅读Mike Ash在Objective-C中读取堆栈和堆对象。
#2
7
Blocks are, by default, allocated on the stack. This is an optimization, since stack allocation is much cheaper than heap allocation. Stack allocation means that, by default again, a block will cease to exist when the scope in which it is declared exits. So a block property with retain
semantics will result in a dangling pointer to a block that doesn't exist anymore.
默认情况下,块在堆栈上分配。这是一种优化,因为堆栈分配比堆分配便宜得多。堆栈分配意味着,默认情况下,当声明的范围退出时,块将不再存在。因此,具有retain语义的块属性将导致指向不再存在的块的悬空指针。
To move a block from the stack to the heap (and thus give it normal Objective-C memory management semantics and an extended lifetime), you must copy the block via [theBlock copy]
, Block_copy(theBlock)
, etc. Once on the heap, the block's lifetime can be managed as needed by retaining/releasing it. (Yes, this applies in ARC too, you just don't have to call -retain
/-release
yourself.)
要将块从堆栈移动到堆(从而为其提供正常的Objective-C内存管理语义和延长的生命周期),必须通过[theBlock copy],Block_copy(theBlock)等复制块。一旦在堆上,块的生命周期可以根据需要通过保留/释放来管理。 (是的,这也适用于ARC,你只需要自己调用-retain / -release。)
So you want to declare block properties with copy
semantics so the block is copied when the property is set, avoiding a dangling pointer to a stack-based block.
因此,您希望使用复制语义声明块属性,以便在设置属性时复制块,从而避免指向基于堆栈的块的悬空指针。
#3
6
The "best practices" you refer to simply say, "Seeing as ARC is going to magically copy your block no matter what you write here, it's best you explicitly write 'copy' so as not to confuse future generations looking at your code."
你所指的“最佳实践”只是简单地说:“无论你在这里写什么,看到ARC都会神奇地复制你的块,你最好明确地写'复制',以免混淆看你代码的后代。”
Explanation follows:
说明如下:
Typically, you shouldn’t need to copy (or retain) a block. You only need to make a copy when you expect the block to be used after destruction of the scope within which it was declared. Copying moves a block to the heap.
–Blocks Programming Topics: Using Blocks, Copying Blocks通常,您不需要复制(或保留)块。当您希望在销毁声明的作用域之后使用该块时,您只需要制作一个副本。复制将块移动到堆。 -Blocks编程主题:使用块,复制块
Clearly, assigning a block to a property means it could be used after the scope it was declared in has been destroyed. Thus, according to Blocks Programming Topics that block should be copied to the heap with Block_copy
.
显然,将一个块分配给一个属性意味着它可以在声明它的范围被破坏后使用。因此,根据Blocks Programming Topics,块应该用Block_copy复制到堆中。
But ARC takes care of this for you:
但是ARC会为您解决这个问题:
Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more.
–Transitioning to ARC在ARC模式下将块传递到堆栈时块“正常工作”,例如在返回中。您不必再调用Block Copy。 - 转换到ARC
Note that this isn't about the retain
semantics the block. There's simply no way for the block's context to exist without being moved off the (soon-to-be-popped) stack and on to the heap. So regardless of what attributes you qualify your @property
with, ARC is still going to copy the block.
请注意,这与块的保留语义无关。块的上下文根本没有办法存在而不会从(即将被弹出的)堆栈移到堆上。因此,无论您使用@property对哪些属性进行限定,ARC仍然会复制该块。
#1
23
By default blocks are created on the stack. Meaning they only exist in the scope they have been created in.
默认情况下,会在堆栈上创建块。这意味着它们只存在于已创建的范围内。
In case you want to access them later they have to be copied to the heap by sending a copy
message to the block object. ARC will do this for you as soon as it detects a block needs to be accessed outside the scope its created in. As a best practise you declare any block property as copy because that's the way it should be under automatic memory management.
如果您想稍后访问它们,则必须通过向块对象发送复制消息将它们复制到堆中。一旦检测到需要在其创建的作用域之外访问块,ARC将立即为您执行此操作。作为最佳实践,您将任何块属性声明为副本,因为这是它应该在自动内存管理下的方式。
Read Stack and Heap Objects in Objective-C by Mike Ash for more info on stack vs. heap.
有关堆栈与堆的更多信息,请阅读Mike Ash在Objective-C中读取堆栈和堆对象。
#2
7
Blocks are, by default, allocated on the stack. This is an optimization, since stack allocation is much cheaper than heap allocation. Stack allocation means that, by default again, a block will cease to exist when the scope in which it is declared exits. So a block property with retain
semantics will result in a dangling pointer to a block that doesn't exist anymore.
默认情况下,块在堆栈上分配。这是一种优化,因为堆栈分配比堆分配便宜得多。堆栈分配意味着,默认情况下,当声明的范围退出时,块将不再存在。因此,具有retain语义的块属性将导致指向不再存在的块的悬空指针。
To move a block from the stack to the heap (and thus give it normal Objective-C memory management semantics and an extended lifetime), you must copy the block via [theBlock copy]
, Block_copy(theBlock)
, etc. Once on the heap, the block's lifetime can be managed as needed by retaining/releasing it. (Yes, this applies in ARC too, you just don't have to call -retain
/-release
yourself.)
要将块从堆栈移动到堆(从而为其提供正常的Objective-C内存管理语义和延长的生命周期),必须通过[theBlock copy],Block_copy(theBlock)等复制块。一旦在堆上,块的生命周期可以根据需要通过保留/释放来管理。 (是的,这也适用于ARC,你只需要自己调用-retain / -release。)
So you want to declare block properties with copy
semantics so the block is copied when the property is set, avoiding a dangling pointer to a stack-based block.
因此,您希望使用复制语义声明块属性,以便在设置属性时复制块,从而避免指向基于堆栈的块的悬空指针。
#3
6
The "best practices" you refer to simply say, "Seeing as ARC is going to magically copy your block no matter what you write here, it's best you explicitly write 'copy' so as not to confuse future generations looking at your code."
你所指的“最佳实践”只是简单地说:“无论你在这里写什么,看到ARC都会神奇地复制你的块,你最好明确地写'复制',以免混淆看你代码的后代。”
Explanation follows:
说明如下:
Typically, you shouldn’t need to copy (or retain) a block. You only need to make a copy when you expect the block to be used after destruction of the scope within which it was declared. Copying moves a block to the heap.
–Blocks Programming Topics: Using Blocks, Copying Blocks通常,您不需要复制(或保留)块。当您希望在销毁声明的作用域之后使用该块时,您只需要制作一个副本。复制将块移动到堆。 -Blocks编程主题:使用块,复制块
Clearly, assigning a block to a property means it could be used after the scope it was declared in has been destroyed. Thus, according to Blocks Programming Topics that block should be copied to the heap with Block_copy
.
显然,将一个块分配给一个属性意味着它可以在声明它的范围被破坏后使用。因此,根据Blocks Programming Topics,块应该用Block_copy复制到堆中。
But ARC takes care of this for you:
但是ARC会为您解决这个问题:
Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more.
–Transitioning to ARC在ARC模式下将块传递到堆栈时块“正常工作”,例如在返回中。您不必再调用Block Copy。 - 转换到ARC
Note that this isn't about the retain
semantics the block. There's simply no way for the block's context to exist without being moved off the (soon-to-be-popped) stack and on to the heap. So regardless of what attributes you qualify your @property
with, ARC is still going to copy the block.
请注意,这与块的保留语义无关。块的上下文根本没有办法存在而不会从(即将被弹出的)堆栈移到堆上。因此,无论您使用@property对哪些属性进行限定,ARC仍然会复制该块。