2017-02-15 140 views
0

在模型的Location類中調用函數求,我得到了當前城市名稱:如何在封閉

var currentLatitude: Double! 
var currentLongitude: Double! 
var currentLocation: String! 
var currentCity: String! 

func getLocationName() { 

    let geoCoder = CLGeocoder() 
    let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude) 

    geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in 
     guard let addressDict = placemarks?[0].addressDictionary else { 
      return 
     } 
     if let city = addressDict["City"] as? String { 
      self.currentCity = city 
      print(city) 
     } 
     if let zip = addressDict["ZIP"] as? String { 
      print(zip) 
     } 
     if let country = addressDict["Country"] as? String { 
      print(country) 
     } 

     self.nowUpdateUI() 
    }) 
} 

在視圖控制器我想更新的用戶界面和更新我的標籤,以顯示當前市。 但是,self.currentCity = city發生在封閉內部。所以,如果我只是運行在視圖控制器等FUNC:

func updateUI() { 
     cityLbl.text = Location.sharedInstance.currentCity 
} 
  • 因爲封還沒有運行完畢,我沒有在任何地方獲得。 我建議添加一個完成處理程序到getLocationName()及其內部,執行對將更新UI的func的調用。 但是,從關閉,完成處理程序的所有教程中,我不清楚如何實現這一點。 如何構建完成處理程序,將其作爲參數傳遞給getLocationName()以及如何從視圖控制器調用getLocationName

回答

2

要處理這種情況,您有多個選項。

  1. 創建delegate/protocol與Location類

    • 創建一個協議並執行該協議的方法與你的ViewController並在Location類中聲明它的實例。之後在的reverseGeocodeLocation中調用這個委託方法。查看有關Protocol的Apple文檔以獲取更多詳細信息。
  2. 您可以用LocationgetLocationName方法創建completionHandler

    • 添加completionHandlergetLocationName,稱那是completionHandlerreverseGeocodeLocation像這樣的completionHandler內。

      func getLocationName(completionHandler: @escaping (_ success: Bool) -> Void) { 
      
          let geoCoder = CLGeocoder() 
          let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude) 
      
          geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in 
           guard let addressDict = placemarks?[0].addressDictionary else { 
            completionHandler(false) 
            return 
           } 
           if let city = addressDict["City"] as? String { 
            self.currentCity = city 
            print(city) 
           } 
           if let zip = addressDict["ZIP"] as? String { 
            print(zip) 
           } 
           if let country = addressDict["Country"] as? String { 
            print(country) 
           } 
           completionHandler(true) 
           //self.nowUpdateUI() 
          }) 
      } 
      
      ViewController

      現在你在哪裏調用此函數調用結束塊內的updateUI方法。

      Location.sharedInstance.getLocationName { (success) in 
          if success {//If successfully got response 
           self.updateUI() 
          } 
      } 
      
  3. 您可以爲(NS)NotificationCenter添加的觀察者。

    • (NS)NotificationCenter註冊觀察者,然後張貼reverseGeocodeLocationcompletionHandler內部通知。你可以通過這個StackOverflow Post得到更多的細節。
+0

如果您有任何疑問,隨時提問。 –

+0

是的,我還沒有流利的編程,你能否展示你提供的第二個選項的實現? (假設updateUI()是視圖控制器中的一個方法,而不是位於其中實現getLocationName的Location)。 –

+0

@Mr_Vlasov所以你想在方法中使用'completionHandler'。你在使用Swift 3嗎? –

0

這整片代碼的:

completionHandler: { placemarks, error in 
     guard let addressDict = placemarks?[0].addressDictionary else { 
      return 
     } 
     if let city = addressDict["City"] as? String { 
      self.currentCity = city 
      print(city) 
     } 
     if let zip = addressDict["ZIP"] as? String { 
      print(zip) 
     } 
     if let country = addressDict["Country"] as? String { 
      print(country) 
     } 

     self.nowUpdateUI() 
    } 

) 

已經在completionHandler(發生後,一切都完了)發生也僅僅是運行updateUI()的completionHandler內。因此,您的最終代碼如下:

completionHandler: { placemarks, error in 
     guard let addressDict = placemarks?[0].addressDictionary else { 
      return 
     } 
     if let city = addressDict["City"] as? String { 
      self.currentCity = city 
      DispatchQueue.main.async { 
       updateUI() 
     } 
     } 
     if let zip = addressDict["ZIP"] as? String { 
      print(zip) 
     } 
     if let country = addressDict["Country"] as? String { 
      print(country) 
     } 

     self.nowUpdateUI() 
    } 

) 

你必須使用DispatchQueue.main是因爲你的completionHandler是在backgroundqueue的原因,但你必須永遠做您從mainQueue,因此用戶UI相關的東西拿到最快改變自己UI沒有任何小故障。想象一下,如果你在後臺線程上做的事情發生得很慢,就會發生這種情況。

+0

但updateUI()是聲明位置標籤的視圖控制器中的一個func。 我應該創建一個視圖控制器的實例並調用func嗎? –

+0

@Mr_Vlasov我明白了,不,你不應該那樣做。你應該做** Nirav D **建議的 – Honey

0
// I thing issue back ground thread you need to update your UI in main thread 
var currentLatitude: Double! 
var currentLongitude: Double! 
var currentLocation: String! 
var currentCity: String! 

func getLocationName() { 

    let geoCoder = CLGeocoder() 
    let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude) 

    geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in 
     guard let addressDict = placemarks?[0].addressDictionary else { 
      return 
     } 
     if let city = addressDict["City"] as? String { 
      self.currentCity = city 
      print(city) 
     } 
     if let zip = addressDict["ZIP"] as? String { 
      print(zip) 
     } 
     if let country = addressDict["Country"] as? String { 
      print(country) 
     } 
     DispatchQueue.main.async { 
      self.nowUpdateUI() 
      // Update your UI in main thread 
     } 

    }) 
}