Trouble with basic callback blocks in Swift - ios

brand new to Swift here. Trying to figure out how to do a very simple call back block from any asynchronous function I write.
For example:
func downloadData(completion: (success: Bool) -> Void){
let success: Bool
//Some asynchronous task here
success = true
//Asynchronous task finished
//Now I want to pass this back
completion(success)
}
I want to be able to call this function and get the value of the success variable in the block. However I'm getting an error "Missing argument label success in call". Don't understand what is going on here. Why would I need to include the argument label? Any pointers on this would be greatly appreciated!

You have the choice:
Either you add the label in the call
completion(success: success)
or you omit the label in the declaration
func downloadData(completion: (Bool) -> Void){
The rule is: all declared labels must be passed.

Related

Does function from argument get captured in closure?

I am trying to clear my code form memory leaks and I am not sure in some situations. I am adding capture lists to all my closures to make them stop capturing and making retain cycles, but not sure about functions passed to closure form arguments... onInternetFailed gets to closure and gets strongly captured.
Situation like this:
public func send<Data>(_ operation: CSOperation<Data>, _ title: String, _ isProgress: Bool,
_ canCancel: Bool, _ isFailedDialog: Bool, _ onInternetFailed: (() -> Void)?,
_ onSuccess: ((Data) -> Void)?) -> CSOperation<Data> {
let process = operation.send(listenOnFailed: false).process!
if isProgress {
let cancelAction = canCancel ? CSDialogAction(title: .cs_dialog_cancel) { [unowned operation] in
operation.cancel()
} : nil
let progress = show(progress: title, cancel: cancelAction)
process.onDone { [unowned progress] _ in progress.hideDialog() }
}
//TODO : does function get captured strongly in closure ?
process.onFailed { [unowned self, unowned operation] failed in
onProcessFailed(operation, failed, title, isProgress, isFailedDialog, onInternetFailed, onSuccess)
}
onSuccess.notNil { [unowned process] in process.onSuccess($0) }
return operation
}
Closures (functions) have reference semantics and will always be captured strongly. In fact, you cannot change the capture mode to weak or unowned. If you think about it, it wouldn't make sense either.
When you deal with completion handlers, the best practice you can follow is to ensure that the completion handlers will be called eventually. This ensures, the closure is released (actually the objects it references).
It's a common programmer error to forget to call a completion handler, or to call it twice. A completion handler must be called once (eventually) and only once. For example, check CSOperation if it actually calls either onFailed or onSuccess when the task completes, when it bails out early, or in any other possible case.
Update
When analysing your code, the object operation returns an object process (presumably holding a strong reference itself).
This process value has a closure value onFailed which will be assigned a closure which imports unowned self, unowned operation and two other closures onInternetFailed and onSuccess.
(I omit the other details).
When you now look at it, it's the value operation that is responsible to hold everything together.
Note also, that there is nowhere a "completion handler" pattern *). Instead, your handlers are kept in instance variables. If these get called, they remain allocated.
So, even if your operation completes, and calls onFailed eventually - nothing gets deallocated.
It's your responsibility to set the "completion handlers" to nil after they have been called. Alternatively, set process to nil, alternatively set operation to `nil.
IMHO, the design should be made more simple and more easy to comprehend.
What I do generally, is to avoid storing "completion" handlers in instance variables. This opens a host of potential errors (due to reference cycles) which you cannot avoid in the code itself, but must be avoided by the caller by enforcing a convention and following strict rules which you have to document, which in turn leads to "leaking implementation details", ...
But you can alleviate the problems by ensuring your "completion handler" will be set to nil once it has been called.
Even, better avoid storing completion handlers in instance variables and apply the "completion handler pattern".
Completion handler pattern
The handler will not be stored in an object as an instance variable:
func doWorkAsync(completion: #escaping (Result) -> Void) {
self.workerQueue.async {
// work
completion(result)
}
}
"Operation Style" variant which clears the completion handler after completion:
class MyOperation {
var completion: ((Result) -> Void)?
init(completion: (Result) -> Void) {
self.completion = completion
}
func start() {
assert(self.completion != nil)
doWorkAsync { result in
let completion = self.completion
self.completion = nil
completion?(result)
}
}
}
Note that - in certain perspective - a Closure is nothing else than an Operation, and an operation can be represented as a Closure. In other words, it's possible to refactor code using Operations and replace it with pure Closures, thus avoiding any issues stemming from using Operations.

#escaping closure actually runs before return

I am implementing download request from a remote source and i ran into the notion of #escaping function. As Apple says:
A closure is said to escape a function when the closure is passed as
an argument to the function, but is called after the function returns.
But I actually noticed (with the breakpoint tool) that it calls and implements before return statement.
static func fetchFeaturedApps(completionHandler: #escaping ([AppCategory]) -> ()) {
let urlString = "https://api.letsbuildthatapp.com/appstore/featured"
URLSession.shared.dataTask(with: URL(string: urlString)!) {
(data, response,error) -> Void in
if error != nil {
print(error?.localizedDescription)
return
}
do {
let json = try(JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) as! Dictionary<String, Any>
var appCategories = [AppCategory]()
// invokes before return [![enter image description here][1]][1]
completionHandler(appCategories)
for dict in json["categories"] as! [[String: Any]] {
let appCategory = AppCategory()
appCategory.setValuesForKeys(dict)
appCategories.append(appCategory)
}
print(appCategories)
DispatchQueue.main.async {
// completionHandler(appCategories)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}.resume()
}
Then and of course after it deals with "completionHandler" it goes on implementing function further, as if i send it plain closure. It turns out #escaping closure call before return statement, strictly in the place where I call it in function body.
But I think maybe I am wrong? Maybe Apple keeps in mind another scenario? Please how do I need to understand #escaping notation with Apples quote about calling them after return? Actually in the example it calls before return , why?
You said:
It turns out #escaping closure [is called] strictly in the place where I call it in function body.
Yep, that's exactly what happens. It's called wherever you place it in your code. If you happen to call it before you return from the method, that's what it's going to do.
As others have pointed out, the fact that it is declared as #escaping means that it can be called later, not that it will necessarily be called later.
In fact, this pattern of calling an #escaping closure synchronously (i.e. before the method returns) is not uncommon. For example, you'll see this if you're dealing with network requests where responses can be cached. In that scenario, you might check your cache and call the closure immediately if the resource has already been retrieved, but call the closure asynchronously if it wasn't previously cached and you have to now retrieve the resource asynchronously from the web. E.g., you might have something like:
func fetchImage(for identifier: String, completion: #escaping (UIImage?) -> Void) {
if let image = cache.retrieveImage(for: identifier) {
completion(image)
return
}
webService.fetchImageAsynchronously(for: identifier) { image in
completion(image)
}
}
Note, just because the closure is designated as #escaping, that doesn't mean that my code path is required to call it asynchronously, regardless. I can call the closure either synchronously or asynchronously, whatever makes sense.
That having been said, if you have a method where you know that you will always call the closure synchronously, you would not use the #escaping designation. Not only would gratuitous use of #escaping in non-escaping scenarios make one's code unclear, but the #escaping designation prevents the compiler from performing certain types of optimizations. So we only use #escaping where it's needed, i.e. in those cases that we know it will or can be called asynchronously.
As it is said in documentation:
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write #escaping before the parameter’s type to indicate that the closure is allowed to escape.
Declaring a closure #escaping does not make it execute after your function returns. It just means that it may or may not execute after function returns, which completely depends on your code.
Concerning your code, your closure is directly called in the function context, so it is no wonder that closure is executed before the function returns. If you would like to make it execute after the function returns, you may want to use some multithreading mechanism, like GCD or OperationQueue.

Swift - CompletionHandler templated as parameter in function (UsingObjectMapper)

I'm trying to pass a completionHandler as a parameter in a function (no problem here).
My problem is that I have multiple precise Types possible that I can recieve in my completionHandler function.
So I thought, "Let's use templates", and I tried.
This is the scheme I want to use:
FuncA(completionHandler as MyType?)
-> FuncB(..){completionHandler(Mappable?)}
-> FuncC(sender: T?){performSegueWithIdentifier("segue", sender)}
Problem:
Func A is printing me an error
Func B seems to be ok
Func C seems to be ok
Do you guy know how to do that, I'm not used to templates yet ??
Thanks for any help :)
I don't believe you can cast completionHandler like that in a method signature. You're going to need to do your typecasting inside the method body. e.g.
typealias handler = () -> Array<AnyObject>
funcA(handler)
func funcA<T>(completion: T?) -> funcB {
if let completion = completion as? handler {
let array = completion()
//do whatever you want here
}
}

Why will func closures sometimes delete its paramter name in Swift?

I have a function of two closures
testNetworkAvailability(reachableBlock:, unreachableBlock:)
But when I hit enter for the autocompletion of closure placeholder, the second one unreachableBlock will delete the variable name along with it and causes an error.
For example, if I open up this closure placeholder by hitting enter, it will look like:
testNetworkAvailability(reachableBlock: { () -> Void in
<#code#>
}) { () -> Void in
<#code#>
}
As a matter of fact, as I copy this function to stackoverflow, the placeholder for these blocks reads as <#(() -> Void)?##() -> Void#>. It is so strange as it should be #() -> Void# only, shouldn't it?
Why is this and how to fix it?
As long as the last argument is a closure, Swift allows you to omit the parameter name and treat it as an inline block.
autoreleasepool {
// ...
}
See the documentation on trailing closures.
Should XCode's autocomplete prefer trailing closures than not is a topic for debate however.

popToViewController Executing First

When the post button is pressed, the function below executes. In the function, all the objects that are retrieved using the Parse backend are appended to the groupConversation array, which is a global array. However, when I reference the array in the UITableViewController that is popped to towards the end of the function and use println() to print the content of the array, the array is empty. However, when I use println() in the UIViewController that contains this function the array is shown to contain one object. In the console, the println() of the UITableViewController that is popped to once the button is pressed, is executed before the println() of the UIViewController that contains the function below. How can I make the functon below execute completely before popping to the UITableViewController.
#IBAction func postButtonPressed(sender: AnyObject) {
//Adds Object To Key
var name=PFObject(className:currentScreen)
name["userPost"] = textView.text
name.saveInBackgroundWithBlock {
(success: Bool!, error: NSError!) -> Void in
if success == true {
self.textView.text=""
} else {
println("TypeMessageViewController Error")
}
}
//Gets all objects of the key
var messageDisplay = PFQuery(className:currentScreen)
messageDisplay.selectKeys(["userPost"])
messageDisplay.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil{
for object in objects {
var textObject = object["userPost"] as String
groupConversation.append(textObject)
}
} else {
// Log details of the failure
}
println("Type message \(groupConversation)")
}
navigationController!.popToViewController(navigationController!.viewControllers[1] as UIViewController, animated: true)
}
The problem is here messageDisplay.findObjectsInBackgroundWithBlock. As you are doing this in background thread, it will be separated from main thread. And your main thread will execute as it should be.
So it before finishing the task you main thread popping the view.
messageDisplay.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil{
for object in objects {
var textObject = object["userPost"] as String
groupConversation.append(textObject)
}
} else {
// Log details of the failure
}
println("Type message \(groupConversation)")
dispatch_async(dispatch_get_main_queue()) {
self.navigationController!.popToViewController(navigationController!.viewControllers[1] as UIViewController, animated: true)
return
}
}
Pushing and popping in background thread may cause problem. So get the main thread after executing the task in background and then pop in main thread.
In swift single statement closures automatically return the statement return value. In your specific case, it's attempting to return an instance of [AnyObject]?, which is the return value of popToViewControllerAnimated. The closure expected by dispatch_afteris Void -> Void instead. Since the closure return type doesn't match, the compiler complains about that.
Hope this helps.. ;)
You are running into a very common issue with asynchronous code. Both your ...InBackgroundWithBlock {} methods run something in the background (async).
The best example I have found to explain it is this:
When you start an async code block, it is like putting eggs on to boil. You also get to include something that should be done when they finish boiling (the block). This might be something like remove the shell and slice the eggs.
If your next bit of code is "butter bread, put eggs on bread" you might get unexpected results. You don't know if the eggs have finished boiling yet, or if the extra tasks (removing shell, slicing) has finished yet.
You have to think in an async way: do this, then when it is finished do this, etc.
In terms of your code, the call to popToViewController() should probably go inside the async block.

Resources