I want to get the address from the coordinate. I have attached my code below..
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let lastLocation = locations.last!
let latvalue = lastLocation.coordinate.latitude
let lngvalue = lastLocation.coordinate.longitude
self.db_latvalue = latvalue
self.db_lngvalue = lngvalue
let location = CLLocation(latitude: latvalue, longitude:lngvalue)
let address = CLGeocoder.init()
address.reverseGeocodeLocation(CLLocation.init(latitude: latvalue, longitude:lngvalue)) { (places, error) in
if error == nil{
if let place = places{
print("addressshowingssq \(place)")
self.db_address = "\(place)"
}
}
}
Output:
[L-30 2nd A Main Road, L-30 2nd A Main Road, HSR Layout, Bengaluru,
Karnataka 560102, India # <+12.91597974,+77.62879254> +/- 100.00m,
region CLCircularRegion (identifier:'<+12.91597974,+77.62879254>
radius 70.94', center:<+12.91597974,+77.62879254>, radius:70.94m)]
I want only the address as i mention below
L-30 2nd A Main Road, L-30 2nd A Main Road, HSR Layout, Bengaluru,
Karnataka 560102
I researched google i got different solution so i got confused.
Update
I have done a few modification to iVarun's solution. This is simpler. and working.
First, add this function:
func geocode(latitude: Double, longitude: Double, completion: #escaping (CLPlacemark?, Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: latitude, longitude: longitude)) { completion($0?.first, $1) }
}
After that,
get the address:
geocode(latitude: latvalue, longitude: lngvalue) { placemark, error in
guard let placemark = placemark, error == nil else { return }
// you should always update your UI in the main thread
DispatchQueue.main.async {
// update UI here
print("address1:", placemark.thoroughfare ?? "")
print("address2:", placemark.subThoroughfare ?? "")
print("city:", placemark.locality ?? "")
print("state:", placemark.administrativeArea ?? "")
print("zip code:", placemark.postalCode ?? "")
print("country:", placemark.country ?? "")
}
}
Result:
address1: Rua Casuarina
address2: 443
city: Rio de Janeiro
state: RJ
zip code: 20975
country: Brazil
As #iOSer indicated, CLPlacemark is capable of giving you this part of the string, However.
You could split the string:
let output:String = "[L-30 2nd A Main Road, L-30 2nd A Main Road, HSR Layout, Bengaluru, Karnataka 560102, India # <+12.91597974,+77.62879254> +/- 100.00m, region CLCircularRegion (identifier:'<+12.91597974,+77.62879254> radius 70.94', center:<+12.91597974,+77.62879254>, radius:70.94m)]"
let items = output.components(separatedBy: "#")
print(items[0])
Becuse the # will be always included, you could skip the rest.
Result:
Hope this will help you:
address.reverseGeocodeLocation(CLLocation.init(latitude: latvalue, longitude:lngvalue)) { (places, error) in
if error == nil{
let placeMark = places! as [CLPlacemark]
if placeMark.count > 0 {
let placeMark = places![0]
var addressString : String = ""
if placeMark.subThoroughfare != nil {
addressString = addressString + placeMark.subThoroughfare! + ", "
}
if placeMark.thoroughfare != nil {
addressString = addressString + placeMark.thoroughfare! + ", "
}
if placeMark.subLocality != nil {
addressString = addressString + placeMark.subLocality! + ", "
}
if placeMark.locality != nil {
addressString = addressString + placeMark.locality! + ", "
}
if placeMark.administrativeArea != nil {
addressString = addressString + placeMark.administrativeArea! + ", "
}
if placeMark.country != nil {
addressString = addressString + placeMark.country! + ", "
}
if placeMark.postalCode != nil {
addressString = addressString + placeMark.postalCode! + " "
}
print(addressString)
}
}
}
Output:
L-30, 2nd A Main Road, HSR Layout, Bengaluru, Karnataka, India, 560102
Swift 3
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
let objLocation = CLLocation(latitude: locValue.latitude, longitude: locValue.longitude)
CLGeocoder().reverseGeocodeLocation(objLocation) { (placemarksArray, error) in
if error != nil {
print("Reverse geocoder failed with error" + (error?.localizedDescription)!)
return
}
if (placemarksArray?.count)! > 0 {
let objPlacemark = placemarksArray?[0]
self.generateAddress(objPlacemark: objPlacemark!)
self.locationManager?.stopUpdatingLocation()
self.locationManager = nil
}
else {
print("Problem with the data received from geocoder")
}
}
}
Function Parsing placemark to string...
func generateAddress(objPlacemark : CLPlacemark) -> String {
print("objPlacemark : \(objPlacemark.description)")
var completeAddress = ""
if objPlacemark.name != nil {
completeAddress = String(describing: objPlacemark.name!)
}
if objPlacemark.thoroughfare != nil && (objPlacemark.name != objPlacemark.thoroughfare) {
completeAddress = completeAddress + ", " + String(describing: objPlacemark.thoroughfare!)
}
if objPlacemark.subThoroughfare != nil {
completeAddress = completeAddress + ", " + String(describing: objPlacemark.subThoroughfare!)
}
if objPlacemark.subLocality != nil {
completeAddress = completeAddress + "," + String(describing: objPlacemark.subLocality!)
}
if objPlacemark.locality != nil {
completeAddress = String(describing: objPlacemark.locality!)
}
if objPlacemark.postalCode != nil {
completeAddress = completeAddress + "," + String(describing: objPlacemark.postalCode!)
}
if objPlacemark.administrativeArea != nil {
completeAddress = completeAddress + "," + String(describing: objPlacemark.administrativeArea!)
}
if objPlacemark.isoCountryCode != nil {
completeAddress = completeAddress + "," + String(describing: objPlacemark.isoCountryCode!)
}
print("completeAddress : \(completeAddress)")
return completeAddress
}
CLGeocodeCompletionHandler contains an array of CLPlacemark. You can access its properties such as name, locality, isoCountryCode etc to form a complete address!!
Related
This question already has answers here:
How do i return coordinates after forward geocoding?
(3 answers)
block until reverseGeocode has returned
(1 answer)
Closed 3 years ago.
I am new swift. I have a task that need to complete. I am getting response from server, where I get numbers of Latitude and Longitude.
{
EndLat = "28.511593";
EndtLong = "77.071136";
},
{
EndLat = "28.511593";
EndtLong = "77.071136";
},.....
getting this type of response having more than 100s of entry.
Now when I'm fetching the address through reverse geocoding..
func getAddressForLogOut(pdblLatitude: String, withLongitude pdblLongitude: String) {
if (pdblLatitude != "") && (pdblLongitude != "") {
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)
self.endAdd = addressString
print("self.endAdd is",self.endAdd)
}
} )
}
}
I'm using that function in tableView's cellForRowAtIndexPath functon. when i scroll the table view the app get crash. getting nil at placemark!
let pm = placemarks! as [CLPlacemark] at this line.
Can any help me to use the reverse geocoding that let me fetching the address of more than 100s of latitude and longitude and show it up in tableView.
CLGeocoder returns an optional type:
typealias CLGeocodeCompletionHandler = ([CLPlacemark]?, Error?) -> Void
(from doc)
you should check it.
I think that usage a cell for data loading from geocoder is bad idea, because you will have a race:
start request1(lat1,lon1)
reusing cell
start request2(lat2,lon2)
response from geocoder for request1
At 4) a cell shows inconsistent data.
I submited my app to app store, they said its crash when app launch. But for my device adn in simulator its working fine. Not able to find whats the issues here.
I attached the binary image with crash file what apple gave me.please let me know any 1 able to get the issue.
Here is that crash file
Thanks
the crash showed here :
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 WCi 0x0000000100df0454 specialized closure #1 in MainScreenViewController.getAdressName(coords:) + 509012 (MainScreenViewController.swift:668)
1 WCi 0x0000000100e01ed4 partial apply for closure #1 in MainScreenViewController.getAdressName(coords:) + 581332 (MainScreenViewController.swift:0)
2 WCi 0x0000000100de0288 _T0SaySo11CLPlacemarkCGSgs5Error_pSgIegxx_So7NSArrayCSgSo7NSErrorCSgIeyByy_TR + 443016 (MainScreenViewController.swift:0)
3 libdispatch.dylib 0x00000001d96596c8 0x1d95f9000 + 394952
4 libdispatch.dylib 0x00000001d965a484 0x1d95f9000 + 398468
5 libdispatch.dylib 0x00000001d96069a4 0x1d95f9000 + 55716
6 CoreFoundation 0x00000001d9bb0df4 0x1d9b05000 + 703988
7 CoreFoundation 0x00000001d9babcbc 0x1d9b05000 + 683196
8 CoreFoundation 0x00000001d9bab1f0 0x1d9b05000 + 680432
9 GraphicsServices 0x00000001dbe24584 0x1dbe19000 + 46468
10 UIKitCore 0x0000000206b38c00 0x206250000 + 9341952
11 WCi 0x0000000100dbeba4 main + 306084 (AppDelegate.swift:23)
12 libdyld.dylib 0x00000001d966abb4 0x1d966a000 + 2996
so in my MainScreenViewController.swift
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if firstload == false {
firstload = true
firstTimeLoads = true
currentlocation = locations.last!
let cityCoords = CLLocation(latitude: currentlocation.coordinate.latitude, longitude: currentlocation.coordinate.longitude)
let addresss = getAdressName(coords: cityCoords)
self.userlat = "\(currentlocation.coordinate.latitude)"
self.userlong = "\(currentlocation.coordinate.longitude)"
self.userDevice = "iOS"
self.userName = Uname ?? "NA"
self.userId = UId ?? "NA"
self.userTime = time
let camera = GMSCameraPosition.init(target: currentlocation.coordinate, zoom: 11, bearing: 0, viewingAngle: 0)
passloc = String(format: "%f,%f", currentlocation.coordinate.latitude,currentlocation.coordinate.longitude)
if let locationData = passloc {
self.movelocation = currentlocation
UserDefaults.standard.set(locationData, forKey: "storemyloc")
UserDefaults.standard.synchronize()
viewmap.animate(to: camera)
self.getAddressFromLatLon(location: currentlocation)
print("my address")
print(currentlocation)
print("LOG: LOCATION 1 \(searchlocation)")
if CLLocationCoordinate2DIsValid(self.searchlocation.coordinate) {
self.movelocation = self.searchlocation
} else {
self.runlink()
}
}
}
}
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.locality != nil {
adressString = adressString + place.name! + " - "
}
if place.thoroughfare != nil {
adressString = adressString + place.subLocality! + ", "
}
if place.locality != nil {
adressString = adressString + place.subAdministrativeArea! + " - "
}
if place.country != nil {
adressString = adressString + place.country!
}
self.Userdic.setValue(adressString, forKey: "useraddress")
self.userAdd = adressString
}
}
}
}
whats might be the issues here for that crash ? Cordinates - lat,long is not passed or issues is with func getAdressName(coords: CLLocation)
Replace your getAdressName with below code.
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.name != nil {
adressString = adressString + place.name! + " - "
}
if place.subLocality != nil {
adressString = adressString + place.subLocality! + ", "
}
if place.subAdministrativeArea != nil {
adressString = adressString + place.subAdministrativeArea! + " - "
}
if place.country != nil {
adressString = adressString + place.country!
}
self.Userdic.setValue(adressString, forKey: "useraddress")
self.userAdd = adressString
}
}
}
}
You checking the nil of locality but inside getting the value of place.subAdministrativeArea! which might in nil case.
I have a marker on map. When scroll map, then the marker also moves. I can find the marker coordinates, but how to find place information using that coordinate?
Place information of current location
func locate() {
placesClient.currentPlace(callback: { (placeLikelihoodList, error) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
let placeInfo = getCurrentPlaceInformation()
self.placeNameLbl.text = placeInfo.name
self.placeAddressLbl.text = placeInfo.address
if let placeLikelihoodList = placeLikelihoodList {
let place = placeLikelihoodList.likelihoods.first?.place
if let place = place {
print("LOG: place name : \(place.name), place Address : \(place.formattedAddress)")
PLACE_NAME = place.name
PLACE_ADDRESS = place.formattedAddress ?? ""
let placeInfo = getCurrentPlaceInformation()
self.placeNameLbl.text = placeInfo.name
self.placeAddressLbl.text = placeInfo.address
}
}
})
}
How to find custom coordinates to find place information?
Apple reverse Geocode API
import CoreLocation
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(<#T##location: CLLocation##CLLocation#>, completionHandler: <#T##CLGeocodeCompletionHandler##CLGeocodeCompletionHandler##([CLPlacemark]?, Error?) -> Void#>)
Google reverse Geocode API
Add GoogleMaps to project (can use pods)
let geocoder = GMSGeocoder()
geocoder.reverseGeocodeCoordinate(position) { response, error in
//
if error != nil {
print("reverse geodcode fail: \(error!.localizedDescription)")
} else {
if let places = response?.results() {
if let place = places.first {
if let lines = place.lines {
print("GEOCODE: Formatted Address: \(lines)")
}
} else {
print("GEOCODE: nil first in places")
}
} else {
print("GEOCODE: nil in places")
}
}
}
func getAddrFrmLtLng(latitude:Any, longitude:Any){
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: latitude as! CLLocationDegrees, longitude: longitude as! CLLocationDegrees)
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
var placeMark: CLPlacemark!
placeMark = placemarks?[0]
self.displayLocationInfo(placemark: placeMark)
})
}
func displayLocationInfo(placemark: CLPlacemark?) -> String {
var locality = ""
var postalCode = ""
var administrativeArea = ""
var country = ""
var sublocality = ""
var throughfare = ""
var name = ""
if let containsPlacemark = placemark {
//stop updating location to save battery life
// locationManager.stopUpdatingLocation()
locality = (containsPlacemark.locality != nil) ? containsPlacemark.locality! : ""
postalCode = (containsPlacemark.postalCode != nil) ? containsPlacemark.postalCode! : ""
administrativeArea = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea! : ""
country = (containsPlacemark.country != nil) ? containsPlacemark.country! : ""
sublocality = (containsPlacemark.subLocality != nil) ? containsPlacemark.subLocality! : ""
throughfare = (containsPlacemark.thoroughfare != nil) ? containsPlacemark.thoroughfare! : ""
}
var adr: String = ""
if throughfare != "" {
adr = throughfare + ", "
}
if sublocality != "" {
adr = adr + sublocality + ", "
}
if locality != "" {
adr = adr + locality + ", "
}
if administrativeArea != "" {
adr = adr + administrativeArea + ", "
}
if postalCode != "" {
adr = adr + postalCode + ", "
}
if country != "" {
adr = adr + country
}
print(adr)
return adr
}
I have got an address from latitude and longitude using reverse Geocoding and set in a label. But the text is not getting multiline. Because cell height is not increased at runtime I used table view cell custom class and set data in table view inside cell custom class and I used below function to get an address and send parameter pdblLatitude and pdblLongitude inside cellForRowAt function
func getAdressName(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) { (placemarks, error) in
if error != nil {
print("Hay un error")
} else {
var addressString : String = ""
let pm = placemarks! as [CLPlacemark]
if pm.count > 0 {
let pm = placemarks![0]
if pm.subLocality != nil {
addressString = addressString + pm.subLocality! + " "
}
if pm.locality != nil {
addressString = addressString + pm.locality! + " "
}
if pm.country != nil {
addressString = addressString + pm.country! + " "
}
print("addressString\(addressString)")
self.lbladdress.text = addressString
self.lbladdress.numberOfLines = 0
self.lbladdress.lineBreakMode = .byWordWrapping
LoadingView.shared.dismiss()
}
}
}
}
I think you have done all required stuff.
Please ensure your lable height is greater then required height.
Please modified your label frame as below, then it will be automatically multiline.
self.lbladdress.frame = Set Label frame as per your text
What I'm trying to do is pass a CLLocation to the function getPlacemarkFromLocation which then uses the passed CLLocation through reverseGeocodeLocation to set the CLPlacemark? that will be returned.
I'm having issues creating the completionHandler closure in reverseGeocodeLocation, it's throwing a compiler error/crash:
In Swift, CLGeocodeCompletionHandler is CLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void according to the documentation AnyObject[]! is supposed to contain CLPlacemark objects just like the Objective-C version.
Here's my current code:
class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{
var g = CLGeocoder()
var p:CLPlacemark?
g.reverseGeocodeLocation(location, completionHandler: {
(placemarks, error) in
let pm = placemarks as? CLPlacemark[]
if (pm && pm?.count > 0){
p = placemarks[0] as? CLPlacemark
}
})
return p?
}
EDIT: It seems like the error had to do with placemarks.count with placemarks not being treated like an array. It compiles now, however I'm getting nothing but nil when trying to set p inside the completionHandler. I've checked the CLLocations being passed and they are valid.
EDIT 2: After printing placemarks, I can confirm that it returns data. However p is still returning nil.
I found the answer I needed in this thread: Set address string with reverseGeocodeLocation: and return from method
The issue lies with the fact that reverseGeocodeLocation is asynchronous, the method is returning a value before the completionBlock sets p in my example.
As requested, here's my current code.
func showAddViewController(placemark:CLPlacemark){
self.performSegueWithIdentifier("add", sender: placemark)
}
func getPlacemarkFromLocation(location: CLLocation){
CLGeocoder().reverseGeocodeLocation(location, completionHandler:
{(placemarks, error) in
if error {println("reverse geodcode fail: \(error.localizedDescription)")}
let pm = placemarks as [CLPlacemark]
if pm.count > 0 { self.showAddPinViewController(placemarks[0] as CLPlacemark) }
})
}
I didn't want to take the NSNotificationCenter route because that would add unnecessary overhead, rather inside the completionHandler closure I call upon another function and pass the CLPlacemark generated by getPlacemarkFromLocation as a parameter to keep things asynchronous since the function will be called after placemarks is set the function (should) receive the placemark needed and execute the code you want. Hope what I said makes sense.
With these lines of Swift, you can print out fully the location's address:
func getLocationAddress(location:CLLocation) {
var geocoder = CLGeocoder()
println("-> Finding user address...")
geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error)->Void in
var placemark:CLPlacemark!
if error == nil && placemarks.count > 0 {
placemark = placemarks[0] as CLPlacemark
var addressString : String = ""
if placemark.ISOcountryCode == "TW" /*Address Format in Chinese*/ {
if placemark.country != nil {
addressString = placemark.country
}
if placemark.subAdministrativeArea != nil {
addressString = addressString + placemark.subAdministrativeArea + ", "
}
if placemark.postalCode != nil {
addressString = addressString + placemark.postalCode + " "
}
if placemark.locality != nil {
addressString = addressString + placemark.locality
}
if placemark.thoroughfare != nil {
addressString = addressString + placemark.thoroughfare
}
if placemark.subThoroughfare != nil {
addressString = addressString + placemark.subThoroughfare
}
} else {
if placemark.subThoroughfare != nil {
addressString = placemark.subThoroughfare + " "
}
if placemark.thoroughfare != nil {
addressString = addressString + placemark.thoroughfare + ", "
}
if placemark.postalCode != nil {
addressString = addressString + placemark.postalCode + " "
}
if placemark.locality != nil {
addressString = addressString + placemark.locality + ", "
}
if placemark.administrativeArea != nil {
addressString = addressString + placemark.administrativeArea + " "
}
if placemark.country != nil {
addressString = addressString + placemark.country
}
}
println(addressString)
}
})
}
Cheers!
Here is closure that worked for me -- it took awhile to get it to work. I think your problem is related to not initializing p with the correct initializer. I tried a few variations until I got this to work: self.placemark = CLPlacemark(placemark: stuff[0] as CLPlacemark)
geocoder.reverseGeocodeLocation(newLocation, completionHandler: {(stuff, error)->Void in
if error {
println("reverse geodcode fail: \(error.localizedDescription)")
return
}
if stuff.count > 0 {
self.placemark = CLPlacemark(placemark: stuff[0] as CLPlacemark)
self.addressLabel.text = String(format:"%# %#\n%# %# %#\n%#",
self.placemark.subThoroughfare ? self.placemark.subThoroughfare : "" ,
self.placemark.thoroughfare ? self.placemark.thoroughfare : "",
self.placemark.locality ? self.placemark.locality : "",
self.placemark.postalCode ? self.placemark.postalCode : "",
self.placemark.administrativeArea ? self.placemark.administrativeArea : "",
self.placemark.country ? self.placemark.country : "")
}
else {
println("No Placemarks!")
return
}
})
EDIT:
moved better answer to its own answer.
EDIT: This doesn't work. The value is nil outside the closure -- see comments below
Your p is nil because the closure is capturing it before it is initialized to a reference. To get the behavior you want you need to make p a non-optional value such as var p : CLPlacemark!.
Below is code I used to test my conjecture:
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
var g = CLGeocoder()
var p:CLPlacemark?
let mynil = "empty"
g.reverseGeocodeLocation(newLocation, completionHandler: {
(placemarks, error) in
let pm = placemarks as? CLPlacemark[]
if (pm && pm?.count > 0){
// p = CLPlacemark()
p = CLPlacemark(placemark: pm?[0] as CLPlacemark)
println("Inside what is in p: \(p?.country ? p?.country : mynil)")
}
})
println("Outside what is in p: \(p?.country ? p?.country : mynil)")
}
Here is console log:
Pushit <- button pressed to start location capturing
Outside what is in p: empty
Inside what is in p: United States
Outside what is in p: empty
Inside what is in p: United States
Outside what is in p: empty...
Bit late to this party, but it looks like you need(ed) to do some ground-up reading about async stuff. Saying that, you've probably learnt it by now.
The basic problem with your code is that p (your placemark) is being set after the function returns, so it's just lost - you can't use a function to return a value with async. With a completion closure, your code is passed the placemark when it arrives (asynchronously) & the closure is invoked - note the function is now returning nothing.
func getPlacemarkFromLocation(_ location: CLLocation, completion: ((CLPlacemark?) -> ())) {
CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in
// use optional chaining to safely return a value or nil
// also using .first rather than checking the count & getting placemarks[0] -
// if the count is zero, will just give you nil
// probably a good idea to check for errors too
completion(placemarks?.first)
})
}
Use -
getPlacemarkFromLocation(myLocation, completion: { (placemark) in
// do something with the placemark here
})
I've not actually put this into Xcode, but it looks right...
Your stuff doesn't work for a number of reasons. Here's the part that I fixed without actually looking at the functionality:
class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{
var g = CLGeocoder()
var p:CLPlacemark?
g.reverseGeocodeLocation(location, completionHandler: {
(placemarks, error) in
let pm = placemarks!
if (pm.count > 0){
p = placemarks![0]
}
})
return p
}