如何从 CloudKit 中存储的位置反转地理编码纬度和经度? - Swift 3

How to reverse geocode latitude and longitude from location stored in CloudKit? - Swift 3

我想弄清楚如何对存储在 CloudKit 中的 CLLocation 进行反向地理编码。我将位置存储在记录中,我知道它存储为纬度和经度。 Here's my record. The latitude and longitude appear I just took them out for now. 但是我希望能够使该位置用户可读,所以也就是对其进行反向地理编码,以获取 城市和州 。到目前为止,我一直在这里查看,但没有关于我可以存储在 CloudKit.

中的位置的反向地理编码

这是我的模型:

class Peek: CloudKitSyncable {

    static let kType = "Peek"
    static let kPhotoData = "photoData"
    static let kTimeStamp = "timestamp"
    static let kTitle = "title"
    static let kText = "text"
    static let kLocation = "location"
    static let kCity = "city"

    let title: String
    let text: String
    let photoData: Data?
    let timestamp: Date
    var location: CLLocation
    var comments: [Comment]
    var photo: UIImage? {

        guard let photoData = self.photoData else { return nil }
        return UIImage(data: photoData)
    }

    init(title: String, timestamp: Date = Date(), text: String, photoData: Data?, comments: [Comment] = [], location: CLLocation) {
        self.title = title
        self.timestamp = timestamp
        self.text = text
        self.photoData = photoData
        self.comments = comments
        self.location = location
    }

    var recordType: String {
        return Peek.kType
    }

    var cloudKitRecordID: CKRecordID?

    convenience required init?(record: CKRecord) {

        guard let timestamp = record.creationDate,
            let photoAsset = record[Peek.kPhotoData] as? CKAsset,
            let title = record[Peek.kTitle] as? String,
            let text = record[Peek.kText] as? String,
        let location = record[Peek.kLocation] as? CLLocation else { return nil }
        let photoData = try? Data(contentsOf: photoAsset.fileURL)
        self.init(title: title, timestamp: timestamp, text: text, photoData: photoData, location: location)
        cloudKitRecordID = record.recordID
    }

    fileprivate var temporaryPhotoURL: URL {
        let temporaryDirectory = NSTemporaryDirectory()
        let temporaryDirectoryURL = URL(fileURLWithPath: temporaryDirectory)
        let fileURL = temporaryDirectoryURL.appendingPathComponent(UUID().uuidString).appendingPathExtension("jpg")

        try? photoData?.write(to: fileURL, options: .atomic)

        return fileURL
    }

}
extension CKRecord {

    convenience init(_ peek: Peek) {
        let recordID = CKRecordID(recordName: UUID().uuidString)
        self.init(recordType: peek.recordType, recordID: recordID)

        self[Peek.kTitle] = peek.title as String? as CKRecordValue?
        self[Peek.kText] = peek.text as String? as CKRecordValue?
        self[Peek.kTimeStamp] = peek.timestamp as CKRecordValue?
        self[Peek.kLocation] = peek.location as CKRecordValue?
        self[Peek.kPhotoData] = CKAsset(fileURL: peek.temporaryPhotoURL)
    }
}

我也有一个 LocationManager 文件:

class LocationManager: NSObject {

    static let sharedInstance = LocationManager()

    override init() {
        super.init()
        locationManager.delegate = self
    }

    var locationManager = CLLocationManager()
    var currentLocation: CLLocation?

    func requestCurrentLocation() {
        locationManager.requestLocation()
    }
}

extension LocationManager: CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        currentLocation = locations.first
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("error: \(error.localizedDescription)")
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            locationManager.requestLocation()
        }
    }
}

Apple 提供了一种内置于 Core Location 的 CLGeocoder class 的方法。 Here are the docs. If successful the completion handler will give you access to an array of CLPlacemark, so you can grab one of those and access whichever human-readable elements you need. The names of the variables are pretty generic to cover locations all over the world, so you'll have to dig in a bit to find exactly what you need. Check the docsCLPlacemark 上获取有关可用变量的确切详细信息。在您的特定情况下,城市和州分别需要 localityadministrativeArea

用法是这样的:

let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
  guard let placemarks = placemarks, let placemark = placemarks.first else { return }
  if let city = placemark.locality, let state = placemark.administrativeArea {
    //Set your labels or whatever
  }
}