2016-12-06 123 views
2

我已經編寫了一個類UserLocation(下面),它使用CoreLocation獲取用戶的當前位置(字符串)&經度和緯度(也是一個字符串「lat,long」傳遞給API)。強制代碼在繼續之前等待對象實例化

我的代碼如下,但是當我初始化這個類的時候,我的代碼的其餘部分在繼續之前沒有等待init完成,所以我錯過了分配位置相關值的機會試圖檢索。這是一個合理的方法(或者我應該考慮一些其他更多的「MVC」組織),如果是這樣,我如何讓我的代碼等待初始化(位置查找&反向地理編碼)來完成繼續前進。有沒有辦法將代碼置於初始化之下,進入某種在類的init中指定的@escaping閉包?我是新來的,所以謝謝你的忠告。

在ViewController.swift的viewDidAppear():

let userLocation = UserLocation() // initializes properly but code below doesn't wait. 
locationsArray[0].name = userLocation.place 
locationsArray[0].coordinates = userLocation.coordinates 

而且我UserLocation.swift類:

import Foundation 
import CoreLocation 

class UserLocation { 
    var place = "" 
    var coordinates = "" 

    let locationManager = CLLocationManager() 
    var currentLocation: CLLocation! 

    init() { 
     returnResults() 
    } 

    func returnResults() { 
     getUserLocation { placemark in 
      if placemark != nil { 
       self.place = (placemark?.name)! 
       self.coordinates = "\((placemark?.location?.coordinate.latitude)!),\((placemark?.location?.coordinate.longitude)!)" 
      } else { 
       print("Error retrieving placemark") 
      } 
     } 
    } 

    func getUserLocation(completion: @escaping (CLPlacemark?) ->()) { 
     var placemark: CLPlacemark? 

     locationManager.requestWhenInUseAuthorization() 

     if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse || 
      CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) { 
      currentLocation = locationManager.location 

      let geoCoder = CLGeocoder() 
      geoCoder.reverseGeocodeLocation(currentLocation) { (placemarks, error) -> Void in 

       if error != nil { 
        print("Error getting location: \(error)") 
        placemark = nil 
       } else { 
        placemark = placemarks?.first 
       } 
       completion(placemark) 
      } 
     } 
    } 
} 

extension CLPlacemark { 
    var cityState: String { 
     var result = "" 
     switch (self.locality, self.administrativeArea, self.country) { 
     case (.some, .some, .some("United States")): 
      result = "\(locality!), \(administrativeArea!)" 
     case (.some, _ , .some): 
      result = "\(locality!), \(country!)" 
     default: 
      result = name ?? "Location Unknown" 
     } 
     return result 
    } 
} 

回答

2

這不一定是斯威夫特的問題。您的問題是由於returnResults以異步方式執行變量設置這一事實引起的,因爲它調用異步函數 - getUserLocation,與異步reverseGeocodeLocation異步(這是CoreLocation的工作方式 - 您不同步獲取位置,但在回調中)。

您不希望等待returnResults執行回調,因爲這意味着阻止主線程,而CoreLocation初始化並嘗試確定位置。相反,您應該通過使用returnResults可用於指示位置檢索完成的完成塊來遵循異步模式。

的一個例子上面會:

class UserLocation { 
    var place = "" 
    var coordinates = "" 

    let locationManager = CLLocationManager() 
    var currentLocation: CLLocation! 

    init() { 
     // don't call anymore from here, let the clients ask for the locations 
    } 

    // This was renamed from returnResults to a more meaningful name 
    // Using the Bool in the completion to signal the success/failure 
    // of the location retrieval 
    func updateLocations(withCompletion completion: @escaping (Bool) -> Void) { 
     getUserLocation { placemark in 
      if placemark != nil { 
       self.place = (placemark?.name)! 
       self.coordinates = "\((placemark?.location?.coordinate.latitude)!),\((placemark?.location?.coordinate.longitude)!)" 
       completion(true) 
      } else { 
       print("Error retrieving placemark") 
       completion(false) 
      } 
     } 
    } 
... 

然後,您可以修改所謂的代碼是這樣的:

let userLocation = UserLocation() 
userLocation.updateLocations { success in 
    guard success else { return } 
    locationsArray[0].name = userLocation.place 
    locationsArray[0].coordinates = userLocation.coordinates 
} 

你不阻塞主線程,和你執行位置可用時的適當代碼。

+0

非常感謝 - 正是我所需要的。非常清晰的語法解釋。非常感激! – Gallaugher

+0

@Gallaugher很高興我能幫上忙 – Cristik

相關問題