Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

swift closure stored and access as a variable

I want to implement a callback in a swift project just like I used to do in Objective-C I need a variable of type closure. That closure should take as a parameter an object and return nothing.

var downloadCompleted: (MLBook) -> (Void)!

When I need to trigger the callback I do this:

if self.downloadCompleted {
   self.downloadCompleted(book)
}

The compiler complains with this error message:

 Type '(MLBook) -> (Void)!' does not conform to protocol 'BooleanType'

If I remove the if statement the compiler says:

Property 'self.downloadCompleted' not initialized

even though it's implicitly unwrapped.

When I try to get the callback:

BookStore.sharedInstance.downloadCompleted{(book: MLBook) -> () in
   println("Print if you got the callback")
}

I get this error message:

'(MLBook) -> ()' is not convertible to 'MLBook'

I'm more worried about the last error message as I'm not quite sure what it is trying to tell me.

Any help would be appreciated. Thanks

like image 551
alex Avatar asked Nov 08 '14 11:11

alex


People also ask

Can a closure be assigned to a variable Swift?

How A Closure Works In 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. You can then pass it around in your code, for instance to another function.

How are closures stored Swift?

Functions and closures are first-class objects in Swift: you can store them, pass them as arguments to functions, and treat them as you would any other value or object. Passing closures as completion handlers is a common pattern in many APIs. Standard Swift library uses closures mostly for event handling and callbacks.

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.

Does closure capture values in Swift?

A closure can capture constants and variables from the surrounding context in which it's defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.


2 Answers

Here is your working example. You have a number of mistakes which the attached illustrates. Note I had the download() method return Bool so that the result can be see in this screen shot.

enter image description here

But, your use of an implicitly unwrapped optional (aka '!') is incorrect. Such an optional is used when the value may be nil but will be assigned at a known time and not changed (see Apple documentation for a description). Your downloadCompleted is a true optional (at least in your example use). Thus, better code, which turns out to be slightly simpler is:

enter image description here

like image 197
GoZoner Avatar answered Sep 19 '22 23:09

GoZoner


2 mistakes. 1st, The whole type should be wrapped in (), then followed a ? or ! as a optional or implicit unwrapped optional. 2nd, you should check with nil, in swift, no implicit boolean conversion.

In your use case, you should use Optional instead of Implicit unwrapped. Because there is big chance that your property has a nil value. With IUO(Implicit unwrapped optional), you skip compiler warning and will get a runtime error.

import Foundation

class MLBook {
    var name = "name"
}

class A {
    var downloadCompleted: ((MLBook) -> Void)?

    func down(){
        var book = MLBook()
        if let cb = self.downloadCompleted {
            cb(book)
        }
    }  
}

var a = A()
a.downloadCompleted = {
    (book: MLBook) -> Void in
    println(book.name)
}

a.down()
like image 34
Shuo Avatar answered Sep 19 '22 23:09

Shuo