You have to get user's current location and then use MKReverseGeocoder to recognize the city.
There's great example in iPhone App Programming Guide, chapter 8.
Once you've got location initialize geocoder, set the delegate and read country from the placemark. Read the documentation for MKReverseGeocodeDelegate and create methods:
What you have to do is setup a CLLocationManager that will find your current coordinates. With the current coordinates you need to use MKReverseGeoCoder to find your location.
- (void)viewDidLoad
{
// this creates the CCLocationManager that will find your current location
CLLocationManager *locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[locationManager startUpdatingLocation];
}
// this delegate is called when the app successfully finds your current location
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// this creates a MKReverseGeocoder to find a placemark using the found coordinates
MKReverseGeocoder *geoCoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate];
geoCoder.delegate = self;
[geoCoder start];
}
// this delegate method is called if an error occurs in locating your current location
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"locationManager:%@ didFailWithError:%@", manager, error);
}
// this delegate is called when the reverseGeocoder finds a placemark
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
MKPlacemark * myPlacemark = placemark;
// with the placemark you can now retrieve the city name
NSString *city = [myPlacemark.addressDictionary objectForKey:(NSString*) kABPersonAddressCityKey];
}
// this delegate is called when the reversegeocoder fails to find a placemark
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
NSLog(@"reverseGeocoder:%@ didFailWithError:%@", geocoder, error);
}
Basically an example would be, after you have created locationManager and CLGeocoder objects just add this code to your viewDidLoad() and then make some labels or text areas to show the data.
If anyone needs it in Swift 3, this is how I did it:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.first!
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, 500, 500)
self.location = location
self.locationManager?.stopUpdatingLocation()
// Drop a pin at user's Current Location
let myAnnotation: MKPointAnnotation = CustomPointAnnotation()
myAnnotation.coordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
myAnnotation.title = "Localização"
self.mapViewMK.addAnnotation(myAnnotation)
self.mapViewMK.setRegion(coordinateRegion, animated: true)
self.locationManager?.stopUpdatingLocation()
self.locationManager = nil
// Get user's current location name
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(self.location!) { (placemarksArray, error) in
if (placemarksArray?.count)! > 0 {
let placemark = placemarksArray?.first
let number = placemark!.subThoroughfare
let bairro = placemark!.subLocality
let street = placemark!.thoroughfare
self.addressLabel.text = "\(street!), \(number!) - \(bairro!)"
}
}
}
After you setup CLLocationManager you would get location update as a latitude/longitude pair. Then you could use CLGeocoder to convert the coordinate to a user friendly place name.
Here is the sample code in Swift 4.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let lastLocation = locations.last {
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(lastLocation) { [weak self] (placemarks, error) in
if error == nil {
if let firstLocation = placemarks?[0],
let cityName = firstLocation.locality { // get the city name
self?.locationManager.stopUpdatingLocation()
}
}
}
}
}
Here is my small Swift class which helps me with getting reverse geocoded information about current location. Don't forget about NSLocationWhenInUseUsageDescription field in Info.plist.
class CurrentPlacemarkUpdater: NSObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
private let geocoder = CLGeocoder()
private(set) var latestPlacemark: CLPlacemark?
var onLatestPlacemarkUpdate: (() -> ())?
var shouldStopOnUpdate: Bool = true
func start() {
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
func stop() {
locationManager.stopUpdatingLocation()
}
fileprivate func updatePlacemark(for location: CLLocation) {
geocoder.reverseGeocodeLocation(location) { [weak self] placemarks, error in
if let placemark = placemarks?.first {
self?.latestPlacemark = placemark
self?.onLatestPlacemarkUpdate?()
if self?.shouldStopOnUpdate ?? false {
self?.stop()
}
}
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
updatePlacemark(for: location)
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("CurrentPlacemarkUpdater: \(error)")
}
}