Swift - 使用未解析的标识符'self' - 来自类中的Closure

时间:2023-01-23 22:43:25

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.

我试图从我的类中声明的闭包中引用我的类中的属性。我无法从我的闭包中访问self,而且我假设self会在我的闭包中引用Class API。

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.

我想声明一个闭包,我稍后将其用作传递给URLSession dataTask的参数(它在没有一个错误行的情况下工作)。我收到标题中列出的错误。

Use of unresolved identifier 'self'

使用未解析的标识符“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.

我找到了这个,但这个例子不同,所以我不确定它是不是同一个bug或我不理解swift。

4 个解决方案

#1


6  

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.

    像Rahul建议的那样将doSomething属性声明为lazy。惰性存储属性是一个属性,其初始值在第一次使用之前不会计算。换句话说,在运行时调用doSomething属性之前不会评估此闭包,此时保证self存在。有关更多详细信息,请参阅Swift编程语言中的Lazy Stored Properties。

  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.

    在doSomething属性中添加一个类型注释,这样编译器就不必在编译时推断出类型,显然它不能做,因为闭包包含self。有关详细信息,请参阅Swift编程语言中的类型安全和类型推断。

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.

PS。欢迎来到Swift编程!这是一种很棒的语言,非常有趣。我希望你能像我一样享受它。

#2


2  

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.

您无法访问self,因为当您在闭包内部调用时它不可用,因为初始化尚未发生,因此编译器会给您错误。

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,因为这将推迟自调用,因为只有在初始化之后才调用lazy var。

 lazy var doSomething = { your closure goes here }

#3


0  

Replace var locations = [Location]() with this var locations : [Location]?

用这个var位置替换var locations = [Location]():[Location]?

and var location : Location! = Location() with self.locations = [Location]() and self.locations.append(location) with self.locations?.append(location)

和var位置:位置! =带有self.locations = [Location]()和self.locations.append(location)的位置()与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是一个太复杂的概念无法掌握我猜,但你可以这样使用它:

lazy var locations:[Location] = {
        let locations = Location()
        return locations
    }()

#4


0  

I have the same questions as you and I solve it using lazy var
Here is a quick example

我有与你相同的问题,我使用lazy var解决它这是一个简单的例子

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

它在我使用self的那一行编译错误但是我把它改成了

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

参考文献:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html http://mikebuss.com/2014/06/22/lazy-initialization-swift/我们应该永远在Swift中使用[unowned self]内部封闭

#1


6  

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.

    像Rahul建议的那样将doSomething属性声明为lazy。惰性存储属性是一个属性,其初始值在第一次使用之前不会计算。换句话说,在运行时调用doSomething属性之前不会评估此闭包,此时保证self存在。有关更多详细信息,请参阅Swift编程语言中的Lazy Stored Properties。

  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.

    在doSomething属性中添加一个类型注释,这样编译器就不必在编译时推断出类型,显然它不能做,因为闭包包含self。有关详细信息,请参阅Swift编程语言中的类型安全和类型推断。

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.

PS。欢迎来到Swift编程!这是一种很棒的语言,非常有趣。我希望你能像我一样享受它。

#2


2  

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.

您无法访问self,因为当您在闭包内部调用时它不可用,因为初始化尚未发生,因此编译器会给您错误。

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,因为这将推迟自调用,因为只有在初始化之后才调用lazy var。

 lazy var doSomething = { your closure goes here }

#3


0  

Replace var locations = [Location]() with this var locations : [Location]?

用这个var位置替换var locations = [Location]():[Location]?

and var location : Location! = Location() with self.locations = [Location]() and self.locations.append(location) with self.locations?.append(location)

和var位置:位置! =带有self.locations = [Location]()和self.locations.append(location)的位置()与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是一个太复杂的概念无法掌握我猜,但你可以这样使用它:

lazy var locations:[Location] = {
        let locations = Location()
        return locations
    }()

#4


0  

I have the same questions as you and I solve it using lazy var
Here is a quick example

我有与你相同的问题,我使用lazy var解决它这是一个简单的例子

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

它在我使用self的那一行编译错误但是我把它改成了

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

参考文献:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html http://mikebuss.com/2014/06/22/lazy-initialization-swift/我们应该永远在Swift中使用[unowned self]内部封闭