In a model's class Location
, I get the name of the current city:
var currentLatitude: Double!
var currentLongitude: Double!
var currentLocation: String!
var currentCity: String!
func getLocationName() {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
return
}
if let city = addressDict["City"] as? String {
self.currentCity = city
print(city)
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
self.nowUpdateUI()
})
}
In view controller I want to update the UI and update my label to show the current city.
However, self.currentCity = city
happens inside of a closure. So if I just run a func in view controller:
func updateUI() {
cityLbl.text = Location.sharedInstance.currentCity
}
getLocationName()
and inside of it, perform the call to a func that will update the UI.
However, from all the tutorials out there on closures, completion handlers, it is not clear to me how to achieve that.
How to construct a completion handler, pass it as an arg to getLocationName()
and how to call getLocationName
from view controller? To handle this situation you have multiple option.
Create delegate/protocol
with your Location class
ViewController
and declare its instance in your Location
class. After then in the completionHandler
of reverseGeocodeLocation
call this delegate method. Check Apple documentation on Protocol
for more details.You can create completionHandler
with your getLocationName
method of Location
class.
Add completionHandler
with getLocationName
and called that completionHandler
inside the completionHandler
of reverseGeocodeLocation
like this way.
func getLocationName(completionHandler: @escaping (_ success: Bool) -> Void) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
completionHandler(false)
return
}
if let city = addressDict["City"] as? String {
self.currentCity = city
print(city)
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
completionHandler(true)
//self.nowUpdateUI()
})
}
Now in ViewController
where you are calling this function call your updateUI
method inside the completion block.
Location.sharedInstance.getLocationName { (success) in
if success {//If successfully got response
self.updateUI()
}
}
You can add observer for (NS)NotificationCenter
.
(NS)NotificationCenter
and then post the notification inside the completionHandler
of reverseGeocodeLocation
. You can get more detail on this with this StackOverflow Post.