代码之家  ›  专栏  ›  技术社区  ›  Adrian rohit chauhan

Swift 4中的反向地理编码

  •  15
  • Adrian rohit chauhan  · 技术社区  · 7 年前

    我试图写一个简单的方法 CLLocationDegrees CLPlacemark . 正在查看 Apple's documentation

    下面是我扔进操场的东西:

    import CoreLocation
    // this is necessary for async code in a playground
    import PlaygroundSupport 
    // this is necessary for async code in a playground
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    func geocode(latitude: CLLocationDegrees, longitude: CLLocationDegrees) -> CLPlacemark? {
        let location = CLLocation(latitude: latitude, longitude: longitude)
        let geocoder = CLGeocoder()
        var placemark: CLPlacemark?
        geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
            if error != nil {
                print("something went horribly wrong")
            }
            if let placemarks = placemarks {
                placemark = placemarks.first
            }
        }
        return placemark
    }
    let myPlacemark = geocode(latitude: 37.3318, longitude: 122.0312)
    

    目前,我的方法是返回零。我不确定我的错误在哪里,但我确信这是我一方的愚蠢之举。谢谢你的阅读。

    2 回复  |  直到 3 年前
        1
  •  34
  •   Leo Dabus    3 年前

    import UIKit
    import CoreLocation
    import PlaygroundSupport
    PlaygroundPage.current.needsIndefiniteExecution = true
    

    func geocode(latitude: Double, longitude: Double, completion: @escaping (_ placemark: [CLPlacemark]?, _ error: Error?) -> Void)  {
        CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: latitude, longitude: longitude)) { placemark, error in
            guard let placemark = placemark, error == nil else {
                completion(nil, error)
                return
            }
            completion(placemark, nil)
        }
    }
    

    或者简单地说:

    func geocode(latitude: Double, longitude: Double, completion: @escaping (_ placemark: [CLPlacemark]?, _ error: Error?) -> Void)  {
        CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: latitude, longitude: longitude), completionHandler: completion)
    }
    

    或扩展CLLocation:

    extension CLLocation {
        func geocode(completion: @escaping (_ placemark: [CLPlacemark]?, _ error: Error?) -> Void) {
            CLGeocoder().reverseGeocodeLocation(self, completionHandler: completion)
        }
    }
    

    要将placemark格式化为邮寄地址,可以使用Contacts framework CNPostalAddressFormatter :

    import Contacts
    
    extension Formatter {
        static let mailingAddress: CNPostalAddressFormatter = {
            let formatter = CNPostalAddressFormatter()
            formatter.style = .mailingAddress
            return formatter
        }()
    }
    
    extension CLPlacemark {
        var mailingAddress: String? {
            postalAddress?.mailingAddress
        }
    }
    
    extension CNPostalAddress {
        var mailingAddress: String {
            Formatter.mailingAddress.string(from: self)
        }
    }
    

    地标

    包含CLPlacemark对象的数组。对于大多数地理编码请求, 此数组应仅包含一个条目。然而,前向地理编码 在以下情况下,请求可能会返回多个placemark对象: 指定的地址无法解析为单个位置。如果 请求已取消或获取位置标记时出错 信息,此参数为零。

    有关CLPlacemark属性的更多信息,请查看 CLPlacemark


    用法:

    let location = CLLocation(latitude: -22.963451, longitude: -43.198242)
    location.geocode { placemark, error in
        if let error = error as? CLError {
            print("CLError:", error)
            return
        } else if let placemark = placemark?.first {
            // you should always update your UI in the main thread
            DispatchQueue.main.async {
                //  update UI here
                print("name:", placemark.name ?? "unknown")
                
                print("address1:", placemark.thoroughfare ?? "unknown")
                print("address2:", placemark.subThoroughfare ?? "unknown")
                print("neighborhood:", placemark.subLocality ?? "unknown")
                print("city:", placemark.locality ?? "unknown")
                
                print("state:", placemark.administrativeArea ?? "unknown")
                print("subAdministrativeArea:", placemark.subAdministrativeArea ?? "unknown")
                print("zip code:", placemark.postalCode ?? "unknown")
                print("country:", placemark.country ?? "unknown", terminator: "\n\n")
                
                print("isoCountryCode:", placemark.isoCountryCode ?? "unknown")
                print("region identifier:", placemark.region?.identifier ?? "unknown")
        
                print("timezone:", placemark.timeZone ?? "unknown", terminator:"\n\n")
    
                // Mailind Address
                print(placemark.mailingAddress ?? "unknown")
            }
        }
    }
    

    这将打印

    姓名:Morro da Saudade

    地址2:597
    社区:拉各亚
    城市:里约热内卢
    州:RJ
    下级行政区:未知
    邮编:22011-040

    等CountryCode:BR
    区域标识符:<-22.96345100,-43.19824200>半径141.83

    鲁木麻黄,597
    拉各亚
    里约热内卢RJ
    22011-040
    巴西

        2
  •  -3
  •   B. Wason    6 年前

    关于堆栈溢出的“reversegecodelocation”有很多问题,我已经见过很多了。我正在使用Swift 4.2,我认为我的“反向代理”请求可能超时了。事实并非如此,当开始使用iPhone时,“didUpdateLocations”周期需要成熟。在“reverseGeocodeLocation”返回placemarks之前,可能需要两个或多个周期。

    我编写了一个简单的应用程序,它使用“reverseGeocodeLocation”,直到在重复“didUpdateLocations”循环后返回“placemarks”。这是我自己开发的“SampleCode”。我从应用程序中学到了很多,它可能会帮助其他人了解反向地理代码请求在现实世界中的工作方式。

    请对可能的改进提出意见。本准则是自由给予和自由获取的。

    import Foundation
    import UIKit
    import CoreLocation
    
    class ViewController: UIViewController, CLLocationManagerDelegate {
        @IBAction func RefreshLocationButton(_ sender: Any) {
            self.requestingPlacemark = true
            self.placemarkData = nil
            //^Make another Placemark Request
            self.requestCounter = 0
            self.RequestCounterLabel.text = ""
            self.LocationLabel.text = ""
            self.PlacemarkLabel.text = ""}
        @IBOutlet weak var LocationCounterLabel: UILabel!
        @IBOutlet weak var RequestCounterLabel: UILabel!
        @IBOutlet weak var LocationLabel: UILabel!
        @IBOutlet weak var PlacemarkLabel: UILabel!
        let locationManager = CLLocationManager()
        var placemarkData: CLPlacemark!
        var placemarkString: String!
        var printPlacemarkData: Bool!
        var didUpdateLocationsCounter: Int = 0
        var requestCounter: Int = 0
        var requestingPlacemark: Bool = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if CLLocationManager.locationServicesEnabled() {
            locationManager.requestAlwaysAuthorization()
            locationManager.delegate = self
            //locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
            locationManager.startUpdatingLocation()
            self.RequestCounterLabel.text = ""
            self.LocationLabel.text = ""
            self.PlacemarkLabel.text = ""}}
    func printPlacemarks() {
        if printPlacemarkData {
            self.placemarkString = "Placemark Data:"
            self.placemarkString = buildPlacemarkString(item: 1)
            self.placemarkString = buildPlacemarkString(item: 2)
            self.placemarkString = buildPlacemarkString(item: 3)
            self.placemarkString = buildPlacemarkString(item: 4)
            self.placemarkString = buildPlacemarkString(item: 5)
            self.placemarkString = buildPlacemarkString(item: 6)
            self.placemarkString = buildPlacemarkString(item: 7)
            self.placemarkString = buildPlacemarkString(item: 8)
            self.placemarkString = buildPlacemarkString(item: 9)
            self.placemarkString = buildPlacemarkString(item: 10)
            self.PlacemarkLabel.text = self.placemarkString
            self.printPlacemarkData = false}}
    func buildPlacemarkString(item: Int) -> String {
        var elementText: String!
        var newString: String!
            switch item {
            case 1: elementText = "name: " + self.placemarkData.name!
            case 2: elementText = "subThoroughfare: " + self.placemarkData.subThoroughfare!
            case 3: elementText = "thoroughfare: " + self.placemarkData.thoroughfare!
            case 4: elementText = "postalCode: " + self.placemarkData.postalCode!
            case 5: elementText = "subLocality: " + self.placemarkData.subLocality!
            case 6: elementText = "locality: " + self.placemarkData.locality!
            case 7: elementText = "subAdministrativeArea: " + self.placemarkData.subAdministrativeArea!
            case 8: elementText = "administrativeArea: " + self.placemarkData.administrativeArea!
            case 9: elementText = "country: " + self.placemarkData.country!
            case 10: elementText = "isoCountryCode: " + self.placemarkData.isoCountryCode!
            default: print("Error: incorrect item number!")}
            newString = self.placemarkString + "\n" + elementText
        return newString
    }
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            //location prints one time and 'didUpdateLocations' is stopped:
        self.didUpdateLocationsCounter = self.didUpdateLocationsCounter + 1
        let labelString = String(describing: self.didUpdateLocationsCounter)
        self.LocationCounterLabel.text = "Location Update Counter: " + labelString
        if self.placemarkData == nil {
            //location variable:
            self.requestCounter = self.requestCounter + 1
            let textString = String(describing: self.requestCounter)
            self.RequestCounterLabel.text = "Request Counter: " + textString
            if locations.count == 0 {
                self.LocationLabel.text = "Locations: There was NONE"}
            else {
                if locations.count > 0 {
                    let coordinate2D: CLLocation = locations.first!
                    let location = CLLocation(latitude: coordinate2D.coordinate.latitude, longitude: coordinate2D.coordinate.longitude)
                    let printString = String(describing: location)
                    self.LocationLabel.text = "Location: " + printString
                    let geocoder: CLGeocoder = CLGeocoder()
                    geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in
                        if error != nil {
                            let errorString = String(describing: error?.localizedDescription)
                            print("reverse geodcode fail: \(errorString)")
                            self.LocationCounterLabel.text = ""
                            self.RequestCounterLabel.text = ""
                            self.LocationLabel.text = "Reverse Geodcode fail: \(errorString)"
                            self.PlacemarkLabel.text = ""
                            self.requestingPlacemark = false
                            return}
                        else {
                            let pm = placemarks! as [CLPlacemark]
                            //There is ALWAYS 'placemarks' Data
                            if pm.count > 0 {
                                self.placemarkData = placemarks![0]
                                self.printPlacemarkData = true
                                self.printPlacemarks()
                                self.requestingPlacemark = false}}})}
                else {
                    if self.requestingPlacemark {
                        self.LocationLabel.text = "Problem: There is no 'location.first'"}}}}}}
    

    然后是情节提要界面:

    Storyboard Image

    View Controller Image

    <?xml version="1.0" encoding="UTF-8"?>
    <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
        <device id="retina4_7" orientation="portrait">
            <adaptation id="fullscreen"/>
        </device>
        <dependencies>
            <deployment identifier="iOS"/>
            <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
            <capability name="Safe area layout guides" minToolsVersion="9.0"/>
            <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
        </dependencies>
        <scenes>
            <!--View Controller-->
            <scene sceneID="tne-QT-ifu">
                <objects>
                    <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="MyThoroughfare" customModuleProvider="target" sceneMemberID="viewController">
                        <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                            <subviews>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Location Counter" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZIg-u9-TMR">
                                    <rect key="frame" x="16" y="20" width="343" height="20.5"/>
                                    <color key="backgroundColor" red="0.80000001190000003" green="0.80000001190000003" blue="0.80000001190000003" alpha="1" colorSpace="calibratedRGB"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Location Count Label" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="csF-KS-xGE">
                                    <rect key="frame" x="16" y="48" width="343" height="20.5"/>
                                    <color key="backgroundColor" red="0.80000001190000003" green="0.80000001190000003" blue="0.80000001190000003" alpha="1" colorSpace="calibratedRGB"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Location String" lineBreakMode="tailTruncation" numberOfLines="8" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qOc-gk-gSp">
                                    <rect key="frame" x="16" y="76" width="343" height="20.5"/>
                                    <color key="backgroundColor" red="0.80000001190000003" green="0.80000001190000003" blue="0.80000001190000003" alpha="1" colorSpace="calibratedRGB"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Placemark String" lineBreakMode="tailTruncation" numberOfLines="14" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="42A-nO-tNf">
                                    <rect key="frame" x="16" y="104" width="343" height="20.5"/>
                                    <color key="backgroundColor" red="0.80000001190000003" green="0.80000001190000003" blue="0.80000001190000003" alpha="1" colorSpace="calibratedRGB"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HgN-oB-ds0">
                                    <rect key="frame" x="121.5" y="578" width="132" height="30"/>
                                    <state key="normal" title="Request Placemark"/>
                                    <connections>
                                        <action selector="RefreshLocationButton:" destination="BYZ-38-t0r" eventType="touchUpInside" id="izY-S5-wjg"/>
                                    </connections>
                                </button>
                            </subviews>
                            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <constraints>
                                <constraint firstItem="ZIg-u9-TMR" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="16" id="6HO-kN-l1z"/>
                                <constraint firstItem="qOc-gk-gSp" firstAttribute="top" secondItem="csF-KS-xGE" secondAttribute="bottom" constant="7.5" id="6ux-dx-gJr"/>
                                <constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="42A-nO-tNf" secondAttribute="trailing" constant="16" id="8dG-gV-Cob"/>
                                <constraint firstItem="HgN-oB-ds0" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="A38-Nt-i3D"/>
                                <constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="ZIg-u9-TMR" secondAttribute="trailing" constant="16" id="Bb0-YC-oov"/>
                                <constraint firstItem="csF-KS-xGE" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="16" id="FJU-ha-HkL"/>
                                <constraint firstItem="42A-nO-tNf" firstAttribute="top" secondItem="qOc-gk-gSp" secondAttribute="bottom" constant="7.5" id="SpR-XB-MLG"/>
                                <constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="HgN-oB-ds0" secondAttribute="bottom" constant="59" id="Vr6-QE-230"/>
                                <constraint firstItem="42A-nO-tNf" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="16" id="aHo-kJ-aCb"/>
                                <constraint firstItem="csF-KS-xGE" firstAttribute="top" secondItem="ZIg-u9-TMR" secondAttribute="bottom" constant="7.5" id="c63-Mq-ItW"/>
                                <constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="csF-KS-xGE" secondAttribute="trailing" constant="16" id="dlV-Hc-8XJ"/>
                                <constraint firstItem="qOc-gk-gSp" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="16" id="m5y-Q8-jxI"/>
                                <constraint firstItem="ZIg-u9-TMR" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="sdw-WQ-Bx9"/>
                                <constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="qOc-gk-gSp" secondAttribute="trailing" constant="16" id="woB-ig-i5v"/>
                            </constraints>
                            <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                        </view>
                        <connections>
                            <outlet property="LocationCounterLabel" destination="ZIg-u9-TMR" id="K4g-WT-f82"/>
                            <outlet property="LocationLabel" destination="qOc-gk-gSp" id="Cdw-bw-EWt"/>
                            <outlet property="PlacemarkLabel" destination="42A-nO-tNf" id="dMh-bw-cRE"/>
                            <outlet property="RequestCounterLabel" destination="csF-KS-xGE" id="ai6-zn-Toi"/>
                        </connections>
                    </viewController>
                    <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
                </objects>
                <point key="canvasLocation" x="53.600000000000001" y="66.11694152923539"/>
            </scene>
        </scenes>
    </document>