9

This Question references this Question: How to simplify callback logic with a Block?

My header has these typedefs

typedef void (^StuffDoneBlock)(NSDictionary * parsedData);
typedef void (^StuffFailedBlock)(NSError * error);

And in init

stuffDoneCallback = Block_copy(done);
StuffFailedCallback = Block_copy(error);

In this paper its says that Block_copy is unnecessary. But then it needs a bridged cast. The compiler message is at follows:

error: cast of block pointer type 'StuffDoneBlock' (aka 'void (^)(NSDictionary *__strong)') to C pointer type 'const void *' requires a bridged cast [4]
         stuffDoneCallback = _bridge(Block_copy(done));
                                     ^~~~~~~~~~~~~~~~
/Developer-4.2/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/include/Block.h:60:61: note: instantiated from:
 #define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
                                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Community
  • 1
  • 1
zeiteisen
  • 7,078
  • 5
  • 50
  • 68

1 Answers1

22

First off, why are you even using Block_copy()? Unless you're writing raw C, you should be calling -copy on the block instead, as in [done copy]. Secondly, ARC will copy blocks for you that need to live past their initialization scope[1], so you don't need to even call -copy anymore. The only "exception" is that block-typed properties still need to have the copy attribute.

[1]: Clarification appears to be needed here. ARC only implicitly copies blocks when the compiler sees that it needs to live past its initialization scope. This basically means when it's assigned to a variable that escapes the current scope (stack variable declared in a parent scope, instance variable, static, etc.). However, if it's passed as an argument to a method/function, the compiler does not do any automatic copying. Typically this isn't a problem because block-aware methods/functions that need to hold onto the block past the stack frame (dispatch_async(), completion blocks, etc.) will copy them for you. However, APIs that are not block-aware (such as NSArray) will not implicitly copy the block, since they expect that a simple -retain will do the trick. If you're passing your block to a non-block-aware API and the block needs to live past the current scope, you must use an explicit -copy.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • I had a `NSMutableArray` of blocks that segfaulted when released with ARC. The segfault went away when I started passing copies of the blocks (obtained through `[block copy]`) to the array, so this suggests that it's actually necessary to explicitly copy the blocks under some circumstances. – zneak Dec 08 '11 at 05:33
  • Yes, APIs which don't expect to take blocks do require you to `-copy` the block if it's going to live past the current scope. That has nothing to do with ARC, since it's not reasonable to expect ARC to copy all blocks passed to other methods/functions. – Lily Ballard Dec 08 '11 at 07:01
  • In that case, you might consider an edit. The sentence "Secondly, ARC will copy blocks for you that need to live past their initialization scope, so you don't need to even call `-copy` anymore." seems to indicate the opposite. – zneak Dec 08 '11 at 17:23
  • @zneak: "live past their initialization scope" means they live in a location visible to the compiler that will exist outside the scope. In other words, if you declare a stack variable, enter a scope, assign a block to the variable, exit the scope, ARC will have copied the block for you. Similarly if you assign it to an ivar or static. However if you pass it to a method (or assign to a property), that method is then responsible for knowing whether or not the block needs to be copied. If the method is compiled with ARC and it knows it has a block, that will also probably Just Work™. – Lily Ballard Dec 08 '11 at 19:22
  • @zneak: The only real problem arises when you pass a block to a method that takes an arbitrary obj-c object and doesn't know it has just been handed a block. The normal behavior there is, if the object needs to live past the stack frame, the API will `-retain` it. However blocks need to be `-copy`'d. So in this one case only will you need to explicitly copy your block. – Lily Ballard Dec 08 '11 at 19:23
  • I know and agree with all you said. My suggestion is that you promote the precisions you made in your last comment to your answer. – zneak Dec 08 '11 at 23:31