Cocoa阻止作为强大的指针与副本

Pet*_*isu 21 cocoa objective-c objective-c-blocks automatic-ref-counting

我用块做了好几次,就像我有强烈参考的指针一样

我听说你应该使用copy,但是使用块作为指针而不是原始对象的含义是什么?

我从来没有得到编译器的抱怨,我不应该使用

@property (nonatomic, strong) MyBlock block;
Run Code Online (Sandbox Code Playgroud)

但应该使用

@property (nonatomic, copy) MyBlock block;
Run Code Online (Sandbox Code Playgroud)

据我所知,块只是一个对象,所以为什么还要复制?

CRD*_*CRD 48

简答

答案是它是历史的,你是完全正确的,在当前的ARC代码中没有必要使用copystrong属性是好的.例如,局部变量和全局变量也是如此.

答案很长

与其他对象不同,块可以存储在堆栈中,这是一种实现优化,因此与其他编译器优化一样,不应对编写的代码产生直接影响.这种优化有一个常见的情况,即创建一个块,作为方法/函数参数传递,由该函数使用,然后丢弃 - 可以在堆栈上快速分配块,然后在没有堆的情况下处理(动态内存池)参与其中.

将此与局部变量进行比较,其中(a)在堆栈上创建,(b)在拥有函数/方法返回时自动销毁,(c)可以通过地址传递给拥有函数调用的方法/函数.其拥有的函数/方法返回后,无法存储和使用局部变量的地址- 该变量不再存在.

但是,期望对象比它们的创建函数/方法(如果需要)更长,因此与局部变量不同,它们在堆上分配,并且不会根据它们的创建函数/方法返回而自动销毁,而是基于它们是否仍然需要 - 以及这里的"需要"由ARC自动确定.

在堆栈上创建一个块可能会优化一个常见的情况,但它也会导致一个问题 - 如果块需要像对象那样经常使用它的创建者,那么它必须在它的创建者堆栈被销毁之前移动到堆.

当块实现首次发布时,程序员可以看到堆栈上存储块的优化,因为当时编译器无法在需要时自动处理将块移动到堆 - 程序员必须使用函数block_copy()自己完成.

虽然这种方法在低级C世界中可能不是不合适的(并且块是C构造),但让高级Objective-C程序员手动管理编译器优化实际上并不好.随着Apple发布了更新版本的编译器改进.在早期它的程序员们被告知,他们可以代替block_copy(block)[block copy],与正常Objective-C对象配合英寸 然后编译器开始根据需要自动从块中复制块,但这并不总是正式记录.

虽然苹果公司不能摆脱它的起源并且将这样做称为"最佳实践" - 这当然是有争议的,但是没有必要在一段时间内从堆栈中手动复制块.在Apple的Working with Blocks的最新版本2014年9月,他们表示应该使用块值属性copy,但随后立即清理(强调添加):

注意:您应该将copy指定为属性属性,因为需要复制块以跟踪其在原始范围之外的捕获状态.在使用自动引用计数时,您不必担心这一点,因为它会自动发生,但属性属性的最佳做法是显示结果行为.

没有必要"显示结果行为" - 首先将块存储在堆栈上是一种优化,并且应该对代码透明 - 就像其他编译器优化一样,代码应该在没有程序员参与的情况下获得性能优势.

因此,只要您使用ARC和当前的Clang编译器,您就可以像其他对象一样处理块,并且因为块是不可变的,这意味着您不需要复制它们.信任Apple,即使他们似乎怀念"我们手工做事的好时光"并鼓励您在代码中留下历史提醒,copy也不需要.

你的直觉是正确的.

HTH

  • “然后,编译器开始根据需要自动从堆栈中复制块,但这并不总是正式记录在案。” 1)在MRC中,编译器*从不*自动复制块。2)在ARC中,ARC规范指定了一些地方,编译器必须在这些地方复制块指针类型的变量,即在分配给__strong变量时。但是,在某些情况下,例如,如果该块仅用作调用的参数,则仍允许编译器不进行复制。 (2认同)