Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store a Closure completion handler to call later?

I'm working on converting this In-App Purchase tutorial into Swift and have come across an issue trying to save the completion handler. We need to store this completion handler so that it can be called later. I cannot figure out how to store a copy of the closure from the arguments. Specifically, I believe I need to copy it but Xcode states this object doesn't have a copy function.

I've defined it like so:

typealias RequestProductsCompletionHandler = (success: Bool, products: NSArray) -> Void

Here I declare a property for it:

var completionHandler: RequestProductsCompletionHandler?

Then this is where I need to store the passed in completion handler into my property:

func requestProductsWithCompletionHandler(completionBlock: RequestProductsCompletionHandler) -> Void {
    //self.completionHandler = completionBlock.copy() //problem: RequestProductsCompletionHandler does not have a member named copy
}

This is how it was done in the Obj-C tutorial:

typedef void (^RequestProductsCompletionHandler)(BOOL success, NSArray * products);

RequestProductsCompletionHandler _completionHandler;

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
    _completionHandler = [completionHandler copy];
}

And later it is used like so:

_completionHandler(YES, skProducts);
_completionHandler = nil;

EDIT: I've removed the .copy() to prevent the error (also had to make the NSArray optional so that I can set it to nil later). My question is, will it work as expected without explicitly copying it? I don't believe it will because Apple stated closures are reference types. This will store a reference to the original closure which I don't want to do. How does one enforce a copy?

like image 202
Jordan H Avatar asked Sep 05 '14 21:09

Jordan H


People also ask

How do completion handlers work?

A completion handler in Swift is a function that calls back when a task completes. This is why it is also called a callback function. A callback function is passed as an argument into another function. When this function completes running a task, it executes the callback function.

What is difference between closure and completion handler Swift?

Closures are self-contained blocks of functionality that can be passed around and used in your code. Said differently, a closure is a block of code that you can assign to a variable.

Can a closure return a value?

Closures can also return values, and they are written similarly to parameters: you write them inside your closure, directly before the in keyword.

How do you declare a closure variable in Swift?

Swift Closure Declaration Here, parameters - any value passed to closure. returnType - specifies the type of value returned by the closure. in (optional) - used to separate parameters/returnType from closure body.


1 Answers

Yes. It will work as expected.

Whenever you call requestProductsWithCompletionHandler you create a closure and pass it to that function. And as you mentioned, when you set completionHandler you actually set it to be a reference to the given closure.

In Objective C, to store the block as ivar you had to copy a block. That's because a block first residing on the stack memory where it was defined. And copy moved it to the heap memory so it can be used

like image 177
tsafrir Avatar answered Oct 02 '22 19:10

tsafrir