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.
Closures Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages. Closures can capture and store references to any constants and variables from the context in which they’re defined.
Because the sorting closure is passed as an argument to a method, Swift can infer the types of its parameters and the type of the value it returns. The sorted (by:) method is being called on an array of strings, so its argument must be a function of type (String, String) -> Bool.
Here’s a version of doSomething () that captures self by including it in the closure’s capture list, and then refers to self implicitly: If self is an instance of a structure or an enumeration, you can always refer to self implicitly.
Nested functions are closures that have a name and can capture values from their enclosing function. Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
Rahul's explanation is correct, but the suggested answer is ever so slightly incomplete.
Here is a complete solution:
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.
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.
You are not able to access self
because it is not available when you are calling inside the closure as initialization hasn't happened yet and so compiler gives you the error.
The fix would be to user lazy
var as this will defer the self
call because lazy var get called only after initialisation.
lazy var doSomething = { your closure goes here }
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