[iOS] CoreLocation - CLGeocoder


位置情報権限を許可する場合、許可されたデータでユーザーのアドレスを画面に表示したいのですが...CLLocationで得ることができるのはユーザーマシンの座標だけで、経度と緯度もあります...これを使ってユーザーの住所を調べる方法が分かりません.
だからグーグルゲームを頑張ってやっと見つけた!CLGeocodeを利用すればいい!アップルの公式ファイルもあります!CLGeocoderを使用して座標値をアドレスに変換する方法を示します.

CLGeocoder


領域座標と領域名を変換するインタフェース
はい.これが変換インタフェースだと知っていますが、どうやって変換しますか?
はい、読んでみましたが、geocoderオブジェクトは使い捨てオブジェクトで、ネットワークに関連するサービスを利用して、ある座標位置値を取得して、ユーザーが理解できるアドレスを取得することができます.逆に、アドレスで座標情報を取得することができます.
詳細はConverting Between CoordinatesとUser-friendly Places Nameの記事でご覧いただけます.

Converting a Coordinate into a Placemark


公式ファイルによると、CLLocationオブジェクトを持っている場合は、reverseGeocodeLocation(_:completionHandler:)メソッドを呼び出して、位置に対応するCLPlacemarkオブジェクトを取得できます.通常、ユーザが選択した地図の位置アドレスを文字列でユーザに表示しようとすると、これらの操作が実行される.これこそ私に必要な情報です!
コード例を親切に書いてあります.
func lookUpCurrentLocation(completionHandler: @escaping (CLPlacemark?)
                -> Void ) {
    // Use the last reported location.
    if let lastLocation = self.locationManager.location {
        let geocoder = CLGeocoder()
            
        // Look up the location and pass it to the completion handler
        geocoder.reverseGeocodeLocation(lastLocation, 
                    completionHandler: { (placemarks, error) in
            if error == nil {
                let firstLocation = placemarks?[0]
                completionHandler(firstLocation)
            }
            else {
	         // An error occurred during geocoding.
                completionHandler(nil)
            }
        })
    }
    else {
        // No location was available.
        completionHandler(nil)
    }
}
ネットワークベースのタスクのためか、completion handlerを利用して非同期タスクを処理しているようです.私はずっとそのplacemarksでプレイヤーの位置情報を得ることができると思っています.さっそく始めましょう.
まずユーザ位置情報モデルクラスを実現しました~!
class UserLocationInformation {
    var country: String
    var administrativeArea: String
    var subAdministrativeArea: String?
    var locality: String
    var thoroughFare: String
    var subThoroughFare: String
    
    init(country: String, administrativeArea: String, locality: String, thoroughFare: String, subThoroughFare: String) {
        self.country = country
        self.administrativeArea = administrativeArea
        self.locality = country
        self.thoroughFare = thoroughFare
        self.subThoroughFare = subThoroughFare
    }
}
次に,位置情報を受信してアドレスに変換する方法を実施した.私が考えている方法は、geoCoderオブジェクトを作成し、reverseGeocodeLocationメソッドで取得したプレースホルダのアドレスをモデル初期化によって取得することです.
この操作は非同期操作であるため、時間的な問題が発生しました.解決策は、@expervation closureを使用してユーザーロcation Informationオブジェクト初期化タスクをポップアップキャビネットに送信することです.
   private func convertLocationToAddress(with clLocation: CLLocation, localeIdentifier: String, completionHandler: @escaping (UserLocationInformation) -> ()) {
        let locale = Locale(identifier: localeIdentifier)

        let geoCoder = CLGeocoder()
        geoCoder.reverseGeocodeLocation(clLocation, preferredLocale: locale) { placemarks, error in

            if error != nil {
                NSLog("\(String(describing: error))")
                return
            }
            guard let placemark = placemarks?.first,
                  let country = placemark.country,
                  let administrativeArea = placemark.administrativeArea,
                  let locality = placemark.locality,
                  let thoroughFare = placemark.locality,
                  let subThoroughFare = placemark.subThoroughfare
                  else { return }
            completionHandler(UserLocationInformation(country: country, administrativeArea: administrativeArea, locality: locality, thoroughFare: thoroughFare, subThoroughFare: subThoroughFare))
        }
    }
その後,CLLocationManagerDelegateを用いたViewControlメソッドでは,ユーザが切り替え時に呼び出すメソッドにポップアップキャビネットで送信されたキャビネットを受け取り,UI設定を行った.(UI設定は必ずメインスレッドで設定する部分は忘れてはいけません!!)もちろん、ユーザが位置権限を許可した場合にのみ、位置値が使用可能であることが前提です.
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {

        if manager.authorizationStatus == .authorizedWhenInUse {
            guard let coordinate = manager.location?.coordinate else {
                NSLog("Can't locate coordinate")
                return

            }
            let clLocation = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
            
            guard let localeIdentifier = Locale.preferredLanguages.first else { return }
            
            convertLocationToAddress(with: clLocation, localeIdentifier: localeIdentifier) { information in
                DispatchQueue.main.async {
                    self.addLeftBarButtonItems(title: information.thoroughFare)
                }
            }
        }
シミュレータをぐるっと回すと!!

乾杯.私はアドレス情報を受け取って、それがUIに適用することを確認します!
初めて位置情報を勉強したので、今はまだ気まずいですが、もっと簡潔なコードを書くように頑張ります!
[注意]:
Apple Developer Document | CLGeocoder
Apple Developer Document | Converting Between Coordinates and User-Friendly Place Names