CLGeocoder reverseGeocodeLocation Energy leak issues - ios

I am using a CLGeocoder().reverseGeocodeLocation and when it is ran, I get "very high" energy consumption and a bit of Overhead. Here's my code:
if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
var currentLatCoord = Double()
if manager.location?.coordinate.latitude != nil {
currentLatCoord = (manager.location?.coordinate.latitude)!
} else {
currentLatCoord = 0.0
print("oops!")
}
var currentLongCoord = Double()
if manager.location?.coordinate.longitude != nil {
currentLongCoord = (manager.location?.coordinate.longitude)!
} else {
currentLongCoord = 0.0
print("oops!")
}
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: currentLatCoord, longitude: currentLongCoord)) { (placemarks, error) -> Void in
if error != nil {
print("oops!")
print(error)
return
}
let placeArray = placemarks as [CLPlacemark]!
var placeMark: CLPlacemark
placeMark = placeArray![0]
if let thoroughfare = placeMark.addressDictionary?["Thoroughfare"] as? String {
self.locationLabel.text = thoroughfare
} else {
self.locationLabel.text = "Error!"
print("oops!")
}
}
}
Here's the debugger:
If anyone could find out why, and I searched all over for the reasoning behind this and couldn't find it, please let me know!

Related

Domain=kCLErrorDomain Code=8 when fetching location through zipcode

I'm trying to fetch the the latitude and longitude based on the input parameters postal/city and country code. Below is my code, this works fine if enter City and country name but shows error if I enter zipcode and country code. Below is the code. (Note: Location services and app permissions are enabled)
func getLocationFrom(postalCityCode: String, countryCode: String) -> CLLocation? {
let geocoder = CLGeocoder()
var location: CLLocation?
let address = CNMutablePostalAddress()
address.postalCode = postalCityCode
address.country = countryCode
geocoder.geocodePostalAddress(address, preferredLocale: Locale.current) { (placemarks, error) in
guard error == nil else {
print("Error: \(error!)")
return
}
guard let placemark = placemarks?.first else {
print("Error: placemark is nil")
return
}
guard let coordinate = placemark.location?.coordinate else {
print("Error: coordinate is nil")
return
}
location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
print("Found location = \(location)")
}
return location
}
Working input: Shanghai, CN
Failing input: 200040, CN
Edit
Attached updated code as suggested in the answer but still experiencing same issue
Currently, you are using return location before it is set, since geocoder.geocodePostalAddress(...) is an asynchronous function.
That means you need to use a completion handler (for example) to return the location, when it has the results, something like this:
func getLocationFrom(postalCityCode: String, countryCode: String, completion: #escaping ( CLLocation?) -> Void) {
let geocoder = CLGeocoder()
var location: CLLocation?
let address = CNMutablePostalAddress()
address.postalCode = postalCityCode
address.country = countryCode
geocoder.geocodePostalAddress(address, preferredLocale: Locale.current) { (placemarks, error) in
guard error == nil else {
print("Error: \(error!)")
return completion(nil)
}
guard let placemark = placemarks?.first else {
print("Error: placemark is nil")
return completion(nil)
}
guard let coordinate = placemark.location?.coordinate else {
print("Error: coordinate is nil")
return completion(nil)
}
location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
print("\n--> Found location = \(location) \n")
completion(location) // <-- here
}
}
Use it like this:
getLocationFrom(postalCityCode: "200040", countryCode: "CN") { location in
print("\n---> location: \(location) \n")
}
EDIT-1
for testing and isolating the issue, try this code in a new SwiftUI project:
struct ContentView: View {
#State var cityLocation = CLLocation()
var body: some View {
Text(cityLocation.description)
.onAppear {
getLocationFrom(postalCityCode: "200040", countryCode: "CN") { location in
print("\n---> location: \(location) \n")
if let theLocation = location {
cityLocation = theLocation
}
}
}
}
func getLocationFrom(postalCityCode: String, countryCode: String, completion: #escaping ( CLLocation?) -> Void) {
let geocoder = CLGeocoder()
var location: CLLocation?
let address = CNMutablePostalAddress()
address.postalCode = postalCityCode
address.country = countryCode
geocoder.geocodePostalAddress(address, preferredLocale: Locale.current) { (placemarks, error) in
guard error == nil else {
print("Error: \(error!)")
return completion(nil)
}
guard let placemark = placemarks?.first else {
print("Error: placemark is nil")
return completion(nil)
}
guard let coordinate = placemark.location?.coordinate else {
print("Error: coordinate is nil")
return completion(nil)
}
location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
print("\n--> Found location = \(location) \n")
completion(location)
}
}
}

forward geocoding completionHandler is not executing in iOS swift4

I am trying convert to addresses into latlongs to place them on googleMap but, when I pass the address String to geoCoder.geoAddressString(fullAddress) and running application, completionHandler is not executing, I tried with breakpoint at geoCoder.geocodeAddressString(fullAddress) { (placemarks, error) and when I click on stepover it is coming out if the completionHandler..
Now, I have no idea why this is happening... Does anyone know? please Help..
see My code Here:
func loadMarkers() {
for i in 0..<self.professioanlDetailsAH.count {
let fullAddress = "\(self.professioanlDetailsAH[i]["searchAddress"]!)"
if !fullAddress.isEmpty {
var geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(fullAddress) { (placemarks, error) in
guard
let placemarks = placemarks,
let addressLocation = placemarks.first?.location
else {
// handle no location found
return
}
let latitude = addressLocation.coordinate.latitude
let longitude = addressLocation.coordinate.longitude
}
}
}
}
Edit:
func loadMarkers() {
for i in 0..<self.professioanlDetailsAH.count {
print(self.professioanlDetailsAH[i]["firstName"]!)
let fullAddress = "\(self.professioanlDetailsAH[i]["searchAddress"]!)"
print(fullAddress)
if !fullAddress.isEmpty {
geoCoder.geocodeAddressString(fullAddress) {(placemarks, error) in
if error != nil {
print(error!)
}
else{
guard
let placemarks = placemarks,
let addressLocation = placemarks.first?.location
else {return}
let latitude = addressLocation.coordinate.latitude
let longitude = addressLocation.coordinate.longitude
print("lat:\(latitude), long:\(longitude)")
}
}
}
}

Swift - Generate an Address Format from Reverse Geocoding

I am trying to generate a Formatted Full address using CLGeocoder in Swift 3. I referred to this SO thread to get the code given below.
However, sometimes the app crashes with a 'nil' error at the line:
//Address dictionary
print(placeMark.addressDictionary ?? "")
Questions:
How can I concatenate these values retrieved from the GeoCoder to form a full address? (Street + City + etc)
How do I handle the nil error I get when the func is unable to find an address?
Full code:
func getAddress() -> String {
var address: String = ""
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: selectedLat, longitude: selectedLon)
//selectedLat and selectedLon are double values set by the app in a previous process
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark!
placeMark = placemarks?[0]
// Address dictionary
//print(placeMark.addressDictionary ?? "")
// Location name
if let locationName = placeMark.addressDictionary!["Name"] as? NSString {
//print(locationName)
}
// Street address
if let street = placeMark.addressDictionary!["Thoroughfare"] as? NSString {
//print(street)
}
// City
if let city = placeMark.addressDictionary!["City"] as? NSString {
//print(city)
}
// Zip code
if let zip = placeMark.addressDictionary!["ZIP"] as? NSString {
//print(zip)
}
// Country
if let country = placeMark.addressDictionary!["Country"] as? NSString {
//print(country)
}
})
return address;
}
func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String) {
var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
let lat: Double = Double("\(pdblLatitude)")!
//21.228124
let lon: Double = Double("\(pdblLongitude)")!
//72.833770
let ceo: CLGeocoder = CLGeocoder()
center.latitude = lat
center.longitude = lon
let loc: CLLocation = CLLocation(latitude:center.latitude, longitude: center.longitude)
ceo.reverseGeocodeLocation(loc, completionHandler:
{(placemarks, error) in
if (error != nil)
{
print("reverse geodcode fail: \(error!.localizedDescription)")
}
let pm = placemarks! as [CLPlacemark]
if pm.count > 0 {
let pm = placemarks![0]
print(pm.country)
print(pm.locality)
print(pm.subLocality)
print(pm.thoroughfare)
print(pm.postalCode)
print(pm.subThoroughfare)
var addressString : String = ""
if pm.subLocality != nil {
addressString = addressString + pm.subLocality! + ", "
}
if pm.thoroughfare != nil {
addressString = addressString + pm.thoroughfare! + ", "
}
if pm.locality != nil {
addressString = addressString + pm.locality! + ", "
}
if pm.country != nil {
addressString = addressString + pm.country! + ", "
}
if pm.postalCode != nil {
addressString = addressString + pm.postalCode! + " "
}
print(addressString)
}
})
}
Formatting addresses is hard because each country has its own format.
With a few lines of code, you can get the correct address format for each country and let Apple handle the differences.
Since iOS 11, you can get a Contacts framework address:
extension CLPlacemark {
#available(iOS 11.0, *)
open var postalAddress: CNPostalAddress? { get }
}
This extension is part of the Contacts framework.
This means, this feature is invisible to you in the XCode code completion until you do
import Contacts
With this additional import, you can do something like
CLGeocoder().reverseGeocodeLocation(location, preferredLocale: nil) { (clPlacemark: [CLPlacemark]?, error: Error?) in
guard let place = clPlacemark?.first else {
print("No placemark from Apple: \(String(describing: error))")
return
}
let postalAddressFormatter = CNPostalAddressFormatter()
postalAddressFormatter.style = .mailingAddress
var addressString: String?
if let postalAddress = place.postalAddress {
addressString = postalAddressFormatter.string(from: postalAddress)
}
}
and get the address formatted in the format for the country in the address.
The formatter even supports formatting as an attributedString.
Prior to iOS 11, you can convert CLPlacemark to CNPostalAddress yourself and still can use the country specific formatting of CNPostalAddressFormatter.
This is my code for swift 3
func getAdressName(coords: CLLocation) {
CLGeocoder().reverseGeocodeLocation(coords) { (placemark, error) in
if error != nil {
print("Hay un error")
} else {
let place = placemark! as [CLPlacemark]
if place.count > 0 {
let place = placemark![0]
var adressString : String = ""
if place.thoroughfare != nil {
adressString = adressString + place.thoroughfare! + ", "
}
if place.subThoroughfare != nil {
adressString = adressString + place.subThoroughfare! + "\n"
}
if place.locality != nil {
adressString = adressString + place.locality! + " - "
}
if place.postalCode != nil {
adressString = adressString + place.postalCode! + "\n"
}
if place.subAdministrativeArea != nil {
adressString = adressString + place.subAdministrativeArea! + " - "
}
if place.country != nil {
adressString = adressString + place.country!
}
self.lblPlace.text = adressString
}
}
}
}
You can esaily call above funcation like:
let cityCoords = CLLocation(latitude: newLat, longitude: newLon)
cityData(coord: cityCoords)
For fixing the empty address issue, either you can use a class property to hold the appended value or you can use a closure to return the value back to the calling function
For fixing the crash you need to avoid the force unwrapping of optionals
Using a closure you can do it like:
// Using closure
func getAddress(handler: #escaping (String) -> Void)
{
var address: String = ""
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: selectedLat, longitude: selectedLon)
//selectedLat and selectedLon are double values set by the app in a previous process
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark?
placeMark = placemarks?[0]
// Address dictionary
//print(placeMark.addressDictionary ?? "")
// Location name
if let locationName = placeMark?.addressDictionary?["Name"] as? String {
address += locationName + ", "
}
// Street address
if let street = placeMark?.addressDictionary?["Thoroughfare"] as? String {
address += street + ", "
}
// City
if let city = placeMark?.addressDictionary?["City"] as? String {
address += city + ", "
}
// Zip code
if let zip = placeMark?.addressDictionary?["ZIP"] as? String {
address += zip + ", "
}
// Country
if let country = placeMark?.addressDictionary?["Country"] as? String {
address += country
}
// Passing address back
handler(address)
})
}
You can call the method like:
getAddress { (address) in
print(address)
}
To concatenate you can simply replace return address by this :
return "\(locationName), \(street), \(city), \(zip), \(country)"
Keeping it simple - A full Swift 3 & 4 compatible View Controller example for obtaining a formatted address string from user's location (add in the other keys available in CLPlacemark if you want more information in your string):
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let manager = CLLocationManager()
let geocoder = CLGeocoder()
var locality = ""
var administrativeArea = ""
var country = ""
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
manager.stopUpdatingLocation()
geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error) in
if (error != nil) {
print("Error in reverseGeocode")
}
let placemark = placemarks! as [CLPlacemark]
if placemark.count > 0 {
let placemark = placemarks![0]
self.locality = placemark.locality!
self.administrativeArea = placemark.administrativeArea!
self.country = placemark.country!
}
})
}
func userLocationString() -> String {
let userLocationString = "\(locality), \(administrativeArea), \(country)"
return userLocationString
}
}
Calling print(userLocationString()) in this example will print: suburb, state, country
Don't forget to add Privacy - Location When In Use Usage Description to your Info.plist file beforehand, to allow the user to grant permissions to your app to utilise location services.
Here's a 2-3 line version of the answers here:
func getAddress(placemarks: [CLPlacemark]) -> String {
guard let placemark = placemarks.first, !placemarks.isEmpty else {return ""}
let outputString = [placemark.locality,
placemark.subLocality,
placemark.thoroughfare,
placemark.postalCode,
placemark.subThoroughfare,
placemark.country].compactMap{$0}.joined(separator: ", ")
print(outputString)
return outputString
}
func getAddress(from coordinate: CLLocationCoordinate2D, completion: #escaping (String) -> Void) {
let geoCoder = CLGeocoder()
let location = CLLocation.init(latitude: coordinate.latitude, longitude: coordinate.longitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// check for errors
guard let placeMarkArr = placemarks else {
completion("")
debugPrint(error ?? "")
return
}
// check placemark data existence
guard let placemark = placeMarkArr.first, !placeMarkArr.isEmpty else {
completion("")
return
}
// create address string
let outputString = [placemark.locality,
placemark.subLocality,
placemark.thoroughfare,
placemark.postalCode,
placemark.subThoroughfare,
placemark.country].compactMap { $0 }.joined(separator: ", ")
completion(outputString)
})
}
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: vehicleLocation.latitude, longitude: vehicleLocation.latitude), completionHandler: {(placemarks, error) -> Void in
guard error == nil else {completionHandler(nil); return}
guard let place = placemarks else {completionHandler(nil); return}
if place.count > 0 {
let pm = place[0]
var addArray:[String] = []
if let name = pm.name {
addArray.append(name)
}
if let thoroughfare = pm.thoroughfare {
addArray.append(thoroughfare)
}
if let subLocality = pm.subLocality {
addArray.append(subLocality)
}
if let locality = pm.locality {
addArray.append(locality)
}
if let subAdministrativeArea = pm.subAdministrativeArea {
addArray.append(subAdministrativeArea)
}
if let administrativeArea = pm.administrativeArea {
addArray.append(administrativeArea)
}
if let country = pm.country {
addArray.append(country)
}
if let postalCode = pm.postalCode {
addArray.append(postalCode)
}
let addressString = addArray.joined(separator: ",\n")
print(addressString)
completionHandler(addressString)
}
else { completionHandler(nil)}
})
I create my own static class for Geocoding and get attributes of CLPlacemark and obtain a complete address, like "usually" returns Google:
import Foundation
import CoreLocation
class ReverseGeocoding {
static func geocode(latitude: Double, longitude: Double, completion: #escaping (CLPlacemark?, _ completeAddress: String?, Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: latitude, longitude: longitude)) { placemarks, error in
guard let placemark = placemarks?.first, error == nil else {
completion(nil, nil, error)
return
}
let completeAddress = getCompleteAddress(placemarks)
completion(placemark, completeAddress, nil)
}
}
static private func getCompleteAddress(_ placemarks: [CLPlacemark]?) -> String {
guard let placemarks = placemarks else {
return ""
}
let place = placemarks as [CLPlacemark]
if place.count > 0 {
let place = placemarks[0]
var addressString : String = ""
if place.thoroughfare != nil {
addressString = addressString + place.thoroughfare! + ", "
}
if place.subThoroughfare != nil {
addressString = addressString + place.subThoroughfare! + ", "
}
if place.locality != nil {
addressString = addressString + place.locality! + ", "
}
if place.postalCode != nil {
addressString = addressString + place.postalCode! + ", "
}
if place.subAdministrativeArea != nil {
addressString = addressString + place.subAdministrativeArea! + ", "
}
if place.country != nil {
addressString = addressString + place.country!
}
return addressString
}
return ""
}
}
Then the implementation:
ReverseGeocoding.geocode(coordinate: coordinate, completion: { (placeMark, completeAddress, error) in
if let placeMark = placeMark, let completeAddress = completeAddress {
print(placeMark.postalCode)
print(placeMark)
print(completeAddress)
} else {
// do something with the error
}
Finaly the print:
15172
Calle del Arenal, 4, Calle del Arenal, 4, 15172 Oleiros, A Coruña, España # <+43.33190337,-8.37144380> +/- 100.00m, region CLCircularRegion (identifier:'<+43.33190337,-8.37144380> radius 70.84', center:<+43.33190337,-8.37144380>, radius:70.84m)
Calle del Arenal, 4, Oleiros, 15172, A Coruña, España
func convertLatLongToAddress(latitude:Double, longitude:Double) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: latitude, longitude: longitude)
var labelText = ""
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
var placeMark: CLPlacemark!
placeMark = placemarks?[0]
if placeMark != nil {
if let name = placeMark.name {
labelText = name
}
if let subThoroughfare = placeMark.subThoroughfare {
if (subThoroughfare != placeMark.name) && (labelText != subThoroughfare) {
labelText = (labelText != "") ? labelText + "," + subThoroughfare : subThoroughfare
}
}
if let subLocality = placeMark.subLocality {
if (subLocality != placeMark.subThoroughfare) && (labelText != subLocality) {
labelText = (labelText != "") ? labelText + "," + subLocality : subLocality
}
}
if let street = placeMark.thoroughfare {
if (street != placeMark.subLocality) && (labelText != street) {
labelText = (labelText != "") ? labelText + "," + street : street
}
}
if let locality = placeMark.locality {
if (locality != placeMark.thoroughfare) && (labelText != locality) {
labelText = (labelText != "") ? labelText + "," + locality : locality
}
}
if let city = placeMark.subAdministrativeArea {
if (city != placeMark.locality) && (labelText != city) {
labelText = (labelText != "") ? labelText + "," + city : city
}
}
if let state = placeMark.postalAddress?.state {
if (state != placeMark.subAdministrativeArea) && (labelText != state) {
labelText = (labelText != "") ? labelText + "," + state : state
}
}
if let country = placeMark.country {
labelText = (labelText != "") ? labelText + "," + country : country
}
// labelText gives you the address of the place
}
})
}
Here as an improvement I added place name as well. It makes address more meaningful.
func getAddressFromlatLong(lat: Double, long: Double, completion: #escaping (_ address: String) -> Void){
let coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
let geocoder = GMSGeocoder()
var add = ""
geocoder.reverseGeocodeCoordinate(coordinate) { (response, error) in
if let address = response?.firstResult() {
guard let arrAddress = address.lines else {return}
if arrAddress.count > 1 {
add = /(arrAddress[0]) + ", " + /(arrAddress[1])
}else if arrAddress.count == 1 {
add = /(arrAddress[0])
}
completion(add)
}
}
}

How to find nearest location when using reverseGeocodeLocation Swift

I am working with reverseGeocodeLocation and sometime with a given latitude and longitude a 'subThoroughfare' and 'thoroughfare' are not returned. If there a way to get the closest 'subThoroughfare' and 'thoroughfare' to that location?
Here is my code so far:
var nearAddressString = ""
CLGeocoder().reverseGeocodeLocation(userCLLocation, completionHandler: { (placemarks, error) -> Void in
if error != nil {
print(error!)
} else {
if let p = placemarks?[0] {
let subThroughfare = p.subThoroughfare ?? ""
let thoroughfare = p.thoroughfare ?? ""
let subLocality = p.subLocality ?? ""
let subAdministrativeArea = p.subAdministrativeArea ?? ""
let postalCode = p.postalCode ?? ""
nearAddressString = "\(subThroughfare) \(thoroughfare) \n \(subLocality) \n \(subAdministrativeArea) \n \(postalCode)"
print(nearAddressString)
} else {
print("Problem with the data received from geocoder")
}
}
})

Changing a variable value inside reverseGeocodeLocation (Swift2)

I am having an issue changing a string variable value the code looks like this
self.mapView is an MKMapView
what the code does: It grabs the finger touch point and put an annotation in its place and by using CLGeocoder().reverseGeocodeLocation I want to grab the person Address but when I try to store the address in a variable it just returns nil meanwhile directly using annotation.title inside CLGeocoder().reverseGeocodeLocation it does change its value what's the deal here?
func longPressAction(gestureRecognizer: UIGestureRecognizer) {
if (gestureRecognizer.state == UIGestureRecognizerState.Began) {
let touchPoint = gestureRecognizer.locationInView(self.mapView);
let annotation = MKPointAnnotation();
let newCoords = self.mapView.convertPoint(touchPoint, toCoordinateFromView: self.mapView);
let location = CLLocation(latitude: newCoords.latitude, longitude: newCoords.longitude);
var address:String = ""; // Doesn't store here!
CLGeocoder().reverseGeocodeLocation(location) { (placemarks, error) -> Void in
if (error != nil) {
} else {
if let p = placemarks?[0] {
if (p.subThoroughfare != nil) {
address = p.subThoroughfare!;
} else if (p.subThoroughfare == nil && p.thoroughfare != nil) {
address = p.thoroughfare!;
} else if (p.subThoroughfare == nil && p.thoroughfare == nil && p.country != nil) {
address = p.country!;
} else if (p.subThoroughfare == nil && p.thoroughfare == nil && p.country == nil) {
address = "New Place";
}
}
}
}
print(address)
annotation.title = address;
annotation.coordinate = newCoords;
self.mapView.addAnnotation(annotation);
sharedAnnotations.addObject(annotation);
}
Output of print(address) is nil
This happens because you're setting address inside a block. This block is called asynchronously by CLGeocoder().reverseGeocodeLocation when it finishes getting the reverse location. That's why when you try to print it right away in your function, it's empty. If you print it inside the block, you'll see it has the correct value.
Your function could look something like this:
func longPressAction(gestureRecognizer: UIGestureRecognizer) {
if (gestureRecognizer.state == UIGestureRecognizerState.Began) {
let touchPoint = gestureRecognizer.locationInView(self.mapView)
let annotation = MKPointAnnotation()
let newCoords = self.mapView.convertPoint(touchPoint, toCoordinateFromView: self.mapView)
let location = CLLocation(latitude: newCoords.latitude, longitude: newCoords.longitude)
CLGeocoder().reverseGeocodeLocation(location) { [weak self] (placemarks, error) -> Void in
if let strongSelf = self{
if (error != nil) {
} else {
if let p = placemarks?[0] {
var address:String = ""
if (p.subThoroughfare != nil) {
address = p.subThoroughfare!
} else if (p.subThoroughfare == nil && p.thoroughfare != nil) {
address = p.thoroughfare!
} else if (p.subThoroughfare == nil && p.thoroughfare == nil && p.country != nil) {
address = p.country!
} else if (p.subThoroughfare == nil && p.thoroughfare == nil && p.country == nil) {
address = "New Place"
}
print(address)
annotation.title = address
annotation.coordinate = newCoords
strongSelf.mapView.addAnnotation(annotation)
strongSelf.sharedAnnotations.addObject(annotation)
}
}
}
}
}
I show you my example
func returnPlaceMark(coordinate: CLLocationCoordinate2D, completaion: (superPlace: MKPlacemark) -> ()) {
let geocoder = CLGeocoder()
let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
geocoder.reverseGeocodeLocation(location) { (arrayPlaceMark, error) -> Void in
if error == nil {
let firstPlacemark = arrayPlaceMark!.first!
completaion(superPlace: MKPlacemark(placemark: firstPlacemark))
}
}

Resources