Swift – Use of unresolved identifier ‘self’ – from Closure in a Class

swift

I am trying to reference a property in my class from a closure declared in my class. I cannot access self from inside my closure, and I'm assuming self would refer to the Class API from within my closure.

I want to declare a closure that I use later as a parameter to pass to a URLSession dataTask (It works without the one error line). I get the error listed in the title.

Use of unresolved identifier 'self'

I've been writing swift for an entire day now and am just trying things out as a sandbox, so I fully expect some criticism.

class Api {

    struct Location {
        var name = String()
        var author = String()
        var averageRating: String?
        var id = Int()
        var lat = Double()
        var lon = Double()
        var type = String()
    }

    var locations = [Location]()

    var doSomething = {(data: Data?, response: URLResponse?, error: Error?) -> Void in
        if error != nil {
            print(error!.localizedDescription)
        } else {
            do {
                if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {
                    let myResult = json["results"] as! [[String: Any]]
                    var location : Location! = Location()
                    for jsonLocation in myResult {
                        if let name = jsonLocation["name"]{location.name = name as! String}
                        if let author = jsonLocation["author"]{location.author = author as! String}
                        if let id = jsonLocation["id"]{location.id = id as! Int}
                        if let lat = jsonLocation["lat"]{location.lat = lat as! Double}
                        if let lon = jsonLocation["lon"]{location.lon = lon as! Double}
                        if let type = jsonLocation["type"]{location.type = type as! String}

                        //ERROR IS HERE, Why does self not reference class API?
                        self.locations.append(location)
                    }
                }
            } catch {
                print("error in JSONSerialization")
            }
        }
    }
}

I have found this, but this example is different so I wasn't sure if it was the same bug or me not understanding swift.

Best Answer

Rahul's explanation is correct, but the suggested answer is ever so slightly incomplete.

Here is a complete solution:

  1. Declare the doSomething property as lazy as Rahul suggested. A lazy stored property is a property whose initial value is not calculated until the first time it is used. In other words this closure will not be evaluated until the doSomething property is called at run-time, at which point self is guaranteed to exist. See Lazy Stored Properties in the Swift Programming Language for more details.

  2. Add a type annotation to the doSomething property so the compiler doesn't have to infer the type at compile time, which apparently it can't do because the closure includes self. See Type Safety and Type Inference in the Swift Programming Language for more details.

So the complete declaration is:

...
lazy var doSomething: (Data?, URLResponse?, Error?) -> Void = { (data: Data?, response: URLResponse?, error: Error?) -> Void in
...

ps. Welcome to Swift programming! It's a fantastic language and really fun. I hope you enjoy it as much as I do.