user1413558
user1413558

Reputation: 3929

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.

Upvotes: 13

Views: 6838

Answers (3)

Gabriele Petronella
Gabriele Petronella

Reputation: 108101

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.

Upvotes: 33

Lance
Lance

Reputation: 9012

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();

Upvotes: 2

Julien
Julien

Reputation: 3477

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);

Upvotes: 2

Related Questions