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

时间:2017-05-09 13:17:24

标签: swift

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

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

  

使用未解析的标识符'self'

我现在已经写了一整天了,我只是想把它作为一个沙箱,所以我完全期待一些批评。

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")
            }
        }
    }
}

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

4 个答案:

答案 0 :(得分:10)

Rahul的解释是正确的,但建议的答案有点不完整。

这是一个完整的解决方案:

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

  2. doSomething属性添加类型注释,以便编译器不必在编译时推断类型,显然它不能这样做,因为闭包包含self。有关详细信息,请参阅Swift编程语言中的Type Safety and Type Inference

  3. 所以完整的声明是:

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

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

答案 1 :(得分:3)

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

修复将是用户lazy var,因为这将推迟self调用,因为只有在初始化后才会调用lazy var。

 lazy var doSomething = { your closure goes here }

答案 2 :(得分:2)

我和你有同样的问题,我使用gcc来解决它 这是一个简单的例子

我原来的代码是:

lazy var

在我使用class MyClass { let callback:()->() = { self.foo() // Compile error: Use of unresolved identifier "self" } func foo() { print("bar") } } 的那一行编译错误 但我把它改为

self

解决了这个问题

参考文献: 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

答案 3 :(得分:0)

将此var locations = [Location]()

替换为var locations : [Location]?

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

你会好起来的!

懒惰变量是一个太复杂的概念无法掌握我猜,但你可以这样使用它:

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