BeginSheet: block alternative using ARC?

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 Enchilada by another SO question on the 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 

When you enable GC, this does not work with Automatic Reference Counting (ARC). Being new to ARC and blocks, I can't get it to work. How do I change the code to make it work with ARC?

I get that the material Block_release () should go away, but I can’t get past compilation errors saying that you are doing "void *" on "void (^) (NSInteger)", which is prohibited by ARC.

+6
source share
1 answer

ARC does not like conversions in void * , which is what Block_ * functions are expected as arguments because ARC cannot talk about ownership of non-configurable types. You need to use bridges to tell the ARC how it should manage ownership of related objects, or that it should not manage its ownership at all.

You can solve problems with ARC using the following code:

 - (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((__bridge void *)block)]; } - (void)my_blockSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { void (^block)(NSInteger) = (__bridge_transfer id)contextInfo; block(returnCode); } 

In the first method

 Block_copy((__bridge void *)block) 

means the following: discards block to void * using the __bridge . This order tells ARC that it should not control the right to the operand, so ARC will not touch block memory management. Block_copy() , Block_copy() other hand, does a block copy, so you need to balance this copy with the release later.

In the second method

 void (^block)(NSInteger) = (__bridge_transfer id)contextInfo; 

means the following: cast contextInfo to id (a generic object type in Objective-C) with the __bridge_transfer application. This listing tells ARC that it should free contextInfo . Since the block variable is __strong (the default classifier), the block is saved and, at the end of the method, it is finally freed. The end result is that block freed at the end of the method, which is the expected behavior.


Alternatively, you can compile this category with -fno-objc-arc . Xcode allows you to create files in one project with or without ARC support.

+14
source

Source: https://habr.com/ru/post/902957/


All Articles