Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cocoa blocks as strong pointers vs copy

Tags:

I did work several times with blocks as with pointers to which i had strong reference

I heard that you should use copy, but what is the implication in working with blocks as pointers and not with the raw object?

I never got a complain from the compiler, that i should not use

@property (nonatomic, strong) MyBlock block; 

but should use

@property (nonatomic, copy) MyBlock block; 

as far as i know, the block is just an object, so why to preferrer copy anyway?

like image 652
Peter Lapisu Avatar asked Nov 26 '14 15:11

Peter Lapisu


People also ask

Why do you generally create a weak reference when using self in a block?

For many of us, it's best practice to always use weak combined with self inside closures to avoid retain cycles. However, this is only needed if self also retains the closure. By adding weak by default you probably end up working with optionals in a lot of cases while it's actually not needed.

What is __ weak Objective-C?

__weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.

What is @property in Objective-C?

The goal of the @property directive is to configure how an object can be exposed. If you intend to use a variable inside the class and do not need to expose it to outside classes, then you do not need to define a property for it. Properties are basically the accessor methods.

What is __ block Objective-C?

__block is a storage qualifier that can be used in two ways: Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).


1 Answers

Short Answer

The answer is it is historical, you are completely correct that in current ARC code there is no need to use copy and a strong property is fine. The same goes for instance, local and global variables.

Long Answer

Unlike other objects a block may be stored on the stack, this is an implementation optimisation and as such should, like other compiler optimisations, not have direct impact on the written code. This optimisation benefits a common case where a block is created, passed as a method/function argument, used by that function, and then discarded - the block can be quickly allocated on the stack and then disposed of without the heap (dynamic memory pool) being involved.

Compare this to local variables, which (a) created on the stack, (b) are automatically destroyed when the owning function/method returns and (c) can be passed-by-address to methods/functions called by the owning function. The address of a local variable cannot be stored and used after its owning function/method has return - the variable no longer exists.

However objects are expected to outlast their creating function/method (if required), so unlike local variables they are allocated on the heap and are not automatically destroyed based on their creating function/method returning but rather based on whether they are still needed - and "need" here is determined automatically by ARC these days.

Creating a block on the stack may optimise a common case but it also causes a problem - if the block needs to outlast its creator, as objects often do, then it must be moved to the heap before its creators stack is destroyed.

When the block implementation was first released the optimisation of storing blocks on the stack was made visible to programmers as the compiler at that time was unable to automatically handle moving the block to the heap when needed - programmers had to use a function block_copy() to do it themselves.

While this approach might not be out-of-place in the low-level C world (and blocks are C construct), having high-level Objective-C programmers manually manage a compiler optimisation is really not good. As Apple released newer versions of the compiler improvements where made. Early on it programmers were told they could replace block_copy(block) with [block copy], fitting in with normal Objective-C objects. Then the compiler started to automatically copy blocks off stack as needed, but this was not always officially documented.

There has been no need to manually copy blocks off the stack for a while, though Apple cannot shrug off its origins and refers to doing so as "best practice" - which is certainly debatable. In the latest version, Sept 2014, of Apple's Working with Blocks, they stated that block-valued properties should use copy, but then immediately come clean (emphasis added):

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.

There is no need to "show the resultant behavior" - storing the block on the stack in the first place is an optimisation and should be transparent to the code - just like other compiler optimisations the code should gain the performance benefit without the programmer's involvement.

So as long as you use ARC and the current Clang compilers you can treat blocks like other objects, and as blocks are immutable that means you don't need to copy them. Trust Apple, even if they appear to be nostalgic for the "good old days when we did things by hand" and encourage you to leave historical reminders in your code, copy is not needed.

Your intuition was right.

like image 160
CRD Avatar answered Sep 25 '22 19:09

CRD