jos*_*hua 19 location latitude-longitude core-location ios swift
我正在研究Swift3中的应用程序,我有字母问题我无法找到它的答案.
我怎样才能根据纬度和经度知道城市名称和国家短名称?
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{
let locationManager = CLLocationManager()
var latitude: Double = 0
var longitude: Double = 0
override func viewDidLoad() {
super.viewDidLoad()
// For use when the app is open & in the background
locationManager.requestAlwaysAuthorization()
// For use when the app is open
//locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
locationManager.startUpdatingLocation()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
print(location.coordinate)
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if (status == CLAuthorizationStatus.denied){
showLocationDisabledpopUp()
}
}
func showLocationDisabledpopUp() {
let alertController = UIAlertController(title: "Background Location Access Disabled", message: "We need your location", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
let openAction = UIAlertAction(title: "Open Setting", style: .default) { (action) in
if let url = URL(string: UIApplicationOpenSettingsURLString){
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
alertController.addAction(openAction)
self.present(alertController, animated: true, completion: nil)
}
}
Run Code Online (Sandbox Code Playgroud)
Leo*_*bus 28
您可以使用CLGeocoder reverseGeocodeLocation方法获取CLPlacemark,获取国家和地区属性信息.请注意,它是一个异步方法,因此在获取该信息时需要向方法添加完成处理程序:
import UIKit
import MapKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
extension CLLocation {
func fetchCityAndCountry(completion: @escaping (_ city: String?, _ country: String?, _ error: Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(self) { completion($0?.first?.locality, $0?.first?.country, $1) }
}
}
Run Code Online (Sandbox Code Playgroud)
用法
let location = CLLocation(latitude: -22.963451, longitude: -43.198242)
location.fetchCityAndCountry { city, country, error in
guard let city = city, let country = country, error == nil else { return }
print(city + ", " + country) // Rio de Janeiro, Brazil
}
Run Code Online (Sandbox Code Playgroud)
pom*_*nto 17
我建议将Google Maps API与您的项目集成.如果您这样做,您的任务可以通过Google提供的反向地理编码来实现.
此外,Google还有用于IOS开发的Google Maps SDK,这也值得考虑.
UPD:您可以在不将地图集成到项目中的情况下执行此操作.基于此答案,您可以使用对Google API的http请求来实现这一目标.请求:
https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=API_KEY
Run Code Online (Sandbox Code Playgroud)
将返回JSON包含所请求地点信息的对象,包括国家和城市名称.
顺便说一句,我强烈建议使用Alamofire在Swift中发出http请求.
Kha*_*idi 10
您需要的是反向地理编码.正如您已经在顶部声明了一些属性.您需要添加CLGeocoder和CLPlancemark
let locationManager = CLLocationManager()
var location: CLLocation?
let geocoder = CLGeocoder()
var placemark: CLPlacemark?
// here I am declaring the iVars for city and country to access them later
var city: String?
var country: String?
var countryShortName: String?
Run Code Online (Sandbox Code Playgroud)
创建一个可以启动位置服务的功能
func startLocationManager() {
// always good habit to check if locationServicesEnabled
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
Run Code Online (Sandbox Code Playgroud)
完成位置地理编码后,还要创建另一个停止
func stopLocationManager() {
locationManager.stopUpdatingLocation()
locationManager.delegate = nil
}
Run Code Online (Sandbox Code Playgroud)
在视图didLoad或您想要启动位置管理器的任何地方首先添加一个检查
override func viewDidLoad() {
super.viewDidLoad()
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
if authStatus == .denied || authStatus == .restricted {
// add any alert or inform the user to to enable location services
}
// here you can call the start location function
startLocationManager()
}
Run Code Online (Sandbox Code Playgroud)
实现位置管理器didFailedWithError的委托方法
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// print the error to see what went wrong
print("didFailwithError\(error)")
// stop location manager if failed
stopLocationManager()
}
Run Code Online (Sandbox Code Playgroud)
实现位置管理器didUpdateLocations的委托方法
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// if you need to get latest data you can get locations.last to check it if the device has been moved
let latestLocation = locations.last!
// here check if no need to continue just return still in the same place
if latestLocation.horizontalAccuracy < 0 {
return
}
// if it location is nil or it has been moved
if location == nil || location!.horizontalAccuracy > lastLocation.horizontalAccuracy {
location = lastLocation
// stop location manager
stopLocationManager()
// Here is the place you want to start reverseGeocoding
geocoder.reverseGeocodeLocation(lastLocation, completionHandler: { (placemarks, error) in
// always good to check if no error
// also we have to unwrap the placemark because it's optional
// I have done all in a single if but you check them separately
if error == nil, let placemark = placemarks, !placemark.isEmpty {
self.placemark = placemark.last
}
// a new function where you start to parse placemarks to get the information you need
self.parsePlacemarks()
})
}
}
Run Code Online (Sandbox Code Playgroud)
添加parsePlacemarks函数
parsePlacemarks() {
// here we check if location manager is not nil using a _ wild card
if let _ = location {
// unwrap the placemark
if let placemark = placemark {
// wow now you can get the city name. remember that apple refers to city name as locality not city
// again we have to unwrap the locality remember optionalllls also some times there is no text so we check that it should not be empty
if let city = placemark.locality, !city.isEmpty {
// here you have the city name
// assign city name to our iVar
self.city = city
}
// the same story optionalllls also they are not empty
if let country = placemark.country, !country.isEmpty {
self.country = country
}
// get the country short name which is called isoCountryCode
if let countryShortName = placemark.isoCountryCode, !countryShortName.isEmpty {
self.countryShortName = countryShortName
}
}
} else {
// add some more check's if for some reason location manager is nil
}
}
Run Code Online (Sandbox Code Playgroud)
您必须cmd +单击CLPlacemark以查看您可以访问的所有属性,例如街道名称称为通道,并且该号码称为subThoroughfare继续阅读文档以获取更多信息
注意:您必须检查位置错误还有地理编码器错误,我在这里没有实现,但您必须处理这些错误和检查错误代码的最佳位置,其他一切都是苹果文档
更新:检查paresPlacemarks函数,其中我添加了isoCountryCode,它等于country shortName当你已经在使用位置服务时,不需要为google API和Alamofire添加额外的网络调用
这是Swift 4代码:
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
// Here you can check whether you have allowed the permission or not.
if CLLocationManager.locationServicesEnabled()
{
switch(CLLocationManager.authorizationStatus())
{
case .authorizedAlways, .authorizedWhenInUse:
print("Authorize.")
let latitude: CLLocationDegrees = (locationManager.location?.coordinate.latitude)!
let longitude: CLLocationDegrees = (locationManager.location?.coordinate.longitude)!
let location = CLLocation(latitude: latitude, longitude: longitude) //changed!!!
CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in
if error != nil {
return
}else if let country = placemarks?.first?.country,
let city = placemarks?.first?.locality {
print(country)
self.cityNameStr = city
}
else {
}
})
break
case .notDetermined:
print("Not determined.")
self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!")
break
case .restricted:
print("Restricted.")
self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!")
break
case .denied:
print("Denied.")
}
}
}
func showAlertMessage(messageTitle: NSString, withMessage: NSString) ->Void {
let alertController = UIAlertController(title: messageTitle as String, message: withMessage as String, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction!) in
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "Settings", style: .default) { (action:UIAlertAction!) in
if let url = URL(string: "App-Prefs:root=Privacy&path=LOCATION/com.company.AppName") {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
// Fallback on earlier versions
}
}
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion:nil)
}
Run Code Online (Sandbox Code Playgroud)
import Foundation
import CoreLocation
let location = CLLocation(latitude: 37.3321, longitude: -122.0318)
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
guard let placemark = placemarks?.first else {
let errorString = error?.localizedDescription ?? "Unexpected Error"
print("Unable to reverse geocode the given location. Error: \(errorString)")
return
}
let reversedGeoLocation = ReversedGeoLocation(with: placemark)
print(reversedGeoLocation.formattedAddress)
// Apple Inc.,
// 1 Infinite Loop,
// Cupertino, CA 95014
// United States
}
struct ReversedGeoLocation {
let name: String // eg. Apple Inc.
let streetName: String // eg. Infinite Loop
let streetNumber: String // eg. 1
let city: String // eg. Cupertino
let state: String // eg. CA
let zipCode: String // eg. 95014
let country: String // eg. United States
let isoCountryCode: String // eg. US
var formattedAddress: String {
return """
\(name),
\(streetNumber) \(streetName),
\(city), \(state) \(zipCode)
\(country)
"""
}
// Handle optionals as needed
init(with placemark: CLPlacemark) {
self.name = placemark.name ?? ""
self.streetName = placemark.thoroughfare ?? ""
self.streetNumber = placemark.subThoroughfare ?? ""
self.city = placemark.locality ?? ""
self.state = placemark.administrativeArea ?? ""
self.zipCode = placemark.postalCode ?? ""
self.country = placemark.country ?? ""
self.isoCountryCode = placemark.isoCountryCode ?? ""
}
}
Run Code Online (Sandbox Code Playgroud)
CLGeocoder为此,您可以使用CoreLocation 中的 , 。来自苹果文档(强调我的):
用于在地理坐标和地名之间进行转换的单镜头对象。
该类
CLGeocoder提供在坐标(指定为纬度和经度)和该坐标的用户友好表示形式之间进行转换的服务。用户友好的坐标表示通常包括与给定位置相对应的街道、城市、州和国家/地区信息......
此服务与MapKit无关,因此根本不需要您在应用程序中使用/显示地图。
| 归档时间: |
|
| 查看次数: |
25667 次 |
| 最近记录: |