Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save a completion handler as an object

I was wondering if there was a way to "save" a completion handeler.

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{

}

- (void)actionHere {
    completionHandler(UIBackgroundFetchResultNewData);
}

I want to send the result in a different function as shown above.

like image 271
user1413558 Avatar asked Oct 04 '13 00:10

user1413558


3 Answers

tl;dr

declare a copy property (weird syntax, I know... http://fuckingblocksyntax.com/)

@property (nonatomic, copy) void (^completionHandler)(UIBackgroundFetchResult fetchResult);

and use it like follows

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    self.completionHandler = completionHandler;
}

- (void)actionHere {
    if (self.completionHandler)
        self.completionHandler(UIBackgroundFetchResultNewData);
}

Discussion

Blocks are full-fledged objects in Objective-C, BUT they come with a big difference: by default they are allocated on the stack.

If you want to save a reference to a block you have to copy it on the heap, since retaining a a block on the stack won't prevent it to be lost whenever the stack frame is teared down.

In order to copy a block on the heap you have to call the Block_Copy() function. You can optionally call the copy method (which will invoke the previous function for you).

Declaring a property with the copy attribute will make the compiler to automatically insert a copy call whenever you assign the object through the property setter.

like image 67
Gabriele Petronella Avatar answered Oct 14 '22 00:10

Gabriele Petronella


Blocks are objects (yes, real ObjC objects!), the only important thing is you have to copy them (not retain) whenever you want to store them for later use.

So you need to do either:

_myCompletionHandler = [completionHandler copy];

or:

_myCompletionHandler = Block_copy(completionHandler);
like image 2
Julien Avatar answered Oct 14 '22 01:10

Julien


You'll need to declare a property for your block. Here's the syntax:

@property (nonatomic, copy) returnType (^blockName)(parameterTypes);

Then you can just say self.blockName = completionHandler.

And in actionHere just call it like this:

self.blockName();
like image 2
Lance Avatar answered Oct 13 '22 23:10

Lance