2017-05-09 64 views
2

我想從我的類中聲明的閉包中引用我的類中的屬性。我無法從閉包中訪問自己,我假設自己會在我的閉包中引用類API。Swift - 使用未解析的標識符'self' - 從類中的閉包

我想聲明一個閉包,我稍後用它作爲參數傳遞給URLSession dataTask(它的工作方式沒有一個錯誤行)。我在標題中列出了錯誤。

使用未解決的標識符「自我」

我已經整整一天寫迅速,現在和我只是想的東西作爲一個沙箱,所以我完全相信一些批評的。

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,但這個例子是不同的,所以我不知道這是否是同樣的bug或我不理解迅速。

+1

是否有理由使用計算屬性而不是doSomething的函數? – Leon

+0

不,只是我不認爲我需要一個功能。但我可以簡單地使用它。我主要是在試圖學習使用閉包。我明白一個函數是一種閉包,但過去,我不完全知道爲什麼都存在。 – Diesel

+0

是的,所以修復使它成爲一個函數,但我仍然不明白爲什麼函數是一種類型的閉包不起作用。 – Diesel

回答

5

拉胡爾的解釋是正確的,但是在考試中有一點點不完整。

這裏是一個完整的解決方案:

  1. 聲明doSomething財產lazy爲拉胡爾建議。一個懶惰的存儲屬性是一個屬性,其初始值直到第一次使用時才被計算。換句話說,只有在運行時調用doSomething屬性時,纔會評估該閉包,此時self保證存在。有關更多詳細信息,請參見Swift編程語言中的Lazy Stored Properties

  2. doSomething屬性添加一個類型註釋,以便編譯器不必在編譯時推斷該類型,顯然它不能這樣做,因爲閉包包括self。有關更多詳細信息,請參見Swift編程語言中的Type Safety and Type Inference

所以完整的聲明是:

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

PS。歡迎來到Swift編程!這是一種非常棒的語言,非常有趣。我希望你和我一樣喜歡它。

+0

從Swift 3.1開始,這裏關於所需類型註釋的第二個問題似乎不再需要。我剛剛在macOS和IBM的Swift Sandbox上測試了這個功能,它允許您在Linux環境中運行不同版本的Swift:https://swift.sandbox.bluemix.net/ –

2

您無法訪問self,因爲在閉包中調用時它不可用,因爲初始化尚未發生,因此編譯器會給出錯誤。

解決的辦法是對用戶lazy var,因爲這會推遲self調用,因爲懶惰的var只會在初始化後調用。

lazy var doSomething = { your closure goes here } 
+1

我仍然遇到與添加單詞lazy相同的問題。 – Diesel

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 
    }() 
+0

我仍然遇到同樣的問題與兩個修復程序。如果我在懶惰之後將自己從地點刪除,它說「實例成員'位置'不能用於類型'Api'」 – Diesel

0

我有同樣的問題,你和我把它用lazy var
解決下面是一個簡單的例子

我最初的代號是:

class MyClass { 
    let callback:()->() = { 
     self.foo() // Compile error: Use of unresolved identifier "self" 
    } 

    func foo() { 
     print("bar") 
    } 
} 

它在該行編譯錯誤我用self
但我將其更改爲

class MyClass { 
    lazy var callback:()->() = { 
     [unowned self] in 
     self.foo() 
    } 

    func foo() { 
     print("bar") 
    } 
} 

let c = MyClass() 
c.callback() 

是解決了這個問題

參考文獻: 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

相關問題