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?
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.
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.
Closures can also return values, and they are written similarly to parameters: you write them inside your closure, directly before the in keyword.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With