簡體   English   中英

Swift:使用異步方法獲取價值

[英]Swift: get value using async method

我正在為這種情況尋找一兩個好的習慣用法:

我想通過異步反向地理位置調用將CLLocationCoordinate2D轉換為CLPlacemark,作為其他操作序列的一部分。

轉換步驟實際上是一個“實用程序”步驟,因此將大量代碼放入處理程序中以執行“其他操作”感覺就像是結構不良。

我可以將結果存儲在類變量中,但是然后我需要知道異步步驟何時完成,這意味着某種事件觸發或主線程排隊以及超時或其他原因,這似乎也很尷尬。

有標准的方法嗎? 僅將代碼放入處理程序中是否常見?

謝謝!

這是我的上下文的特定代碼FWIW。

func getPlaceFromCoordinate(coordinate: CLLocationCoordinate2D) -> CLPlacemark? {

    var loc = CLLocation(
        latitude: coordinate.latitude,
        longitude: coordinate.longitude
    )

    var mightBeAPlace: CLPlacemark? = nil

    CLGeocoder().reverseGeocodeLocation(loc, completionHandler: {(placemarks, error) -> Void in
        if(error != nil) {
            println("Reverse geocoding error.")
        }
        else if (placemarks.count == 0) {
            println("no placemarks")
        }
        else { // if (placemarks.count > 0)
            println("we have placemarks")
            mightBeAPlace = CLPlacemark(placemark: placemarks[0] as! CLPlacemark)
            println("Inside closure place: \(mightBeAPlace?.locality)")
            lastUserSelectedPlace = mightBeAPlace // This stores it in a class variable.
        }
    })
    println("Outside closure place: \(mightBeAPlace?.locality)")
    return mightBeAPlace // This of course fails because the async task is running separately.
}

典型的方法是自己采用completionHandler方法,例如:

lazy var geocoder = CLGeocoder()

func getPlaceFromCoordinate(coordinate: CLLocationCoordinate2D, completionHandler: (CLPlacemark!, NSError?) -> ()) {
    let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)

    geocoder.reverseGeocodeLocation(location) { placemarks, error in
        if error != nil {
            println("Reverse geocoding error: \(error)")
        } else if placemarks.count == 0 {
            println("no placemarks")
        }

        completionHandler(placemarks.first as? CLPlacemark, error)
    }
}

您可以這樣稱呼它:

getPlaceFromCoordinate(coordinate) { placemark, error in 
    if placemark != nil {
        // use placemark here
    }
}

// but do not use it here, because the above runs asynchronously (i.e. later)

就您在該completionHandler閉包中放入多少代碼以及在getPlaceFromCoordinate放入多少代碼getPlaceFromCoordinate ,這完全是該代碼所需功能的函數。 但是,在getPlaceFromCoordinate內重復執行的許多常規代碼(例如,記錄錯誤,您所擁有的內容)以及希望關閉將限於使用CLPlacemark並更新模型對象和/或UI。

但是,是的,約定是將任何取決於異步方法完成的內容放入完成處理程序中。 盡管有使這種異步方法同步運行的技術,但這通常是一個非常糟糕的主意。

如果發現閉包中的代碼變得笨拙,請進行函數分解,然后將此代碼移至其自己的函數中,並讓完成處理程序簡單地調用它。 或也有其他異步模式(例如,異步NSOperation子類之間具有依賴關系,承諾/未來等)。 但是使用異步模式。

我決定采用的方法是編寫getPlaceFromCoordinate函數以接受可選的閉包,因此調用方法可以控制查找結果的處理方式。

func getPlaceFromCoordinate(
        coordinate: CLLocationCoordinate2D,
        placeAction: ((CLPlacemark) -> Void)?
    ) {

        :
    // Reverse geocode.
        :

    //  If we get a good placemark:
    if (placeAction != nil) {
        placeAction!(placemark)
    }

    }

對於上下文來說,這似乎很合適,很靈活,並且將調用代碼放回“駕駛員座位”中。 不知道還有什么其他利弊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM