Mike Ash created an example of using blocks to handle callbacks from sheets, which seems very nice. This was in turn updated to work with garbage collection by user Enchilada in another SO question at beginSheet: block alternative?, see below.
@implementation NSApplication (SheetAdditions)
- (void)beginSheet:(NSWindow *)sheet modalForWindow:(NSWindow *)docWindow didEndBlock:(void (^)(NSInteger returnCode))block
{
[self beginSheet:sheet
modalForWindow:docWindow
modalDelegate:self
didEndSelector:@selector(my_blockSheetDidEnd:returnCode:contextInfo:)
contextInfo:Block_copy(block)];
}
- (void)my_blockSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
void (^block)(NSInteger returnCode) = contextInfo;
block(returnCode);
Block_release(block);
}
@end
While enabling GC, this does not work with Automatic Reference Counting (ARC). Myself, being a beginner at both ARC and blocks, can't get it to work. How should I modify the code to get it to work with ARC?
I get that the Block_release() stuff needs to go, but I can't get past the compile errors about casting 'void *' to 'void (^)(NSInteger)' being disallowed with ARC.
ARC doesn’t like conversions to
void *
, which is what the Block_* functions expect as arguments, because ARC cannot reason about ownership of non-retainable types. You need to use bridge casts to tell ARC how it should manage the ownership of the objects involved, or that it shouldn’t manage their ownership at all.You can solve the ARC issues by using the code below:
In the first method,
means the following: cast
block
tovoid *
using a__bridge
cast. This cast tells ARC that it shouldn’t manage the ownership of the operand, so ARC won’t touchblock
memory-management-wise. On the other hand,Block_copy()
does copy the block so you need to balance that copy with a release later on.In the second method,
means the following: cast
contextInfo
toid
(the generic object type in Objective-C) with a__bridge_transfer
cast. This cast tells ARC that it should releasecontextInfo
. Since theblock
variable is __strong (the default qualifier), the Block is retained and, at the end of the method, it is finally released. The end result is thatblock
gets released at the end of the method, which is the expected behaviour.Alternatively, you could compile that category with
-fno-objc-arc
. Xcode allows files in the same project to build with or without ARC enabled.