Reputation: 5353
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.
Upvotes: 6
Views: 14520
Reputation: 4146
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.
Upvotes: 14
Reputation: 1964
I have the same questions as you and I solve it using lazy var
Here is a quick example
My originally code is:
class MyClass {
let callback:()->() = {
self.foo() // Compile error: Use of unresolved identifier "self"
}
func foo() {
print("bar")
}
}
It compile error at that line I use self
But I change it to
class MyClass {
lazy var callback:()->() = {
[unowned self] in
self.foo()
}
func foo() {
print("bar")
}
}
let c = MyClass()
c.callback()
that solved the problem
References:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
http://mikebuss.com/2014/06/22/lazy-initialization-swift/
Shall we always use [unowned self] inside closure in Swift
Upvotes: 2
Reputation: 989
Replace var locations = [Location]()
with this var locations : [Location]?
and var location : Location! = Location()
with self.locations = [Location]()
and self.locations.append(location)
with self.locations?.append(location)
You will be good to go!
lazy var is too complex a concept to grasp I guess but you can use it this way:
lazy var locations:[Location] = {
let locations = Location()
return locations
}()
Upvotes: 0
Reputation: 2100
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 }
Upvotes: 6