40

I am able to place annotations on my MKMapView by using latitude and longitude, however, my feed coming in that I need to use location for is using street addresses instead of Lat and Long. e.g 1234 west 1234 east, San Francisco, CA ...

Would this have something to do with the CLLocationManager?

Has anyone attempted this before?

QED
  • 9,803
  • 7
  • 50
  • 87
Romes
  • 3,088
  • 5
  • 37
  • 52
  • Do you mean street address? I'm not sure what you mean by "1234 west 1234 east". – QED Mar 07 '12 at 17:31
  • Yes, by street address. I can get the State, City, and address. If possible, I'd like to convert that street address into Lat and Long. – Romes Mar 07 '12 at 17:34

7 Answers7

76

Based on psoft's excellent information, I was able to achieve what I was looking for with this code.

NSString *location = @"some address, state, and zip";
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
            [geocoder geocodeAddressString:location 
                 completionHandler:^(NSArray* placemarks, NSError* error){
                     if (placemarks && placemarks.count > 0) {
                         CLPlacemark *topResult = [placemarks objectAtIndex:0];
                         MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];

                         MKCoordinateRegion region = self.mapView.region;
                         region.center = placemark.region.center;
                         region.span.longitudeDelta /= 8.0;
                         region.span.latitudeDelta /= 8.0;

                         [self.mapView setRegion:region animated:YES];
                         [self.mapView addAnnotation:placemark];
                     }
                 }
             ];
Romes
  • 3,088
  • 5
  • 37
  • 52
  • 8
    Setting the region.center as shown is deprecated and setting the span to 1/8 of the current span won't always make sense. This would be simpler: `MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(placemark.coordinate, 5000, 5000);` (the 5000 is in meters). –  Jul 07 '14 at 12:34
  • 2
    Always use `firstObject` instead of `objectAtIndex:0` – Laszlo Sep 30 '15 at 12:10
  • 1
    Just as a side note, `if (placemarks && placemarks.count > 0)` is redundant as `placemarks.count` will return `0` if placemarks is `nil`. It can be replaced with `if (placemarks.count > 0)`. – hhanesand Dec 30 '15 at 23:46
  • In case anyone was wondering the completionHandler gets called on the main thread – keji Jan 21 '16 at 23:12
16

Refactored Swift version:

let location = "some address, state, and zip"
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(location) { [weak self] placemarks, error in
    if let placemark = placemarks?.first, let location = placemark.location {
        let mark = MKPlacemark(placemark: placemark)

        if var region = self?.mapView.region {
            region.center = location.coordinate
            region.span.longitudeDelta /= 8.0
            region.span.latitudeDelta /= 8.0
            self?.mapView.setRegion(region, animated: true)
            self?.mapView.addAnnotation(mark)
        }
    }
}
NatashaTheRobot
  • 6,879
  • 4
  • 32
  • 27
11

What you're after is called geocoding or forward-geocoding. Reverse-geocoding is the process of converting a lat/long pair to street address.

iOS5 provides the CLGeocoder class for geocoding. MKPlacemark supports reverse-goecoding in iOS >= 3.0. The data involved of course is very large, so your app will generally need network access to the functionality.

A good place to start is Apple's Location Awareness Programming Guide. Also, there are LOTS of questions about this here on SO. https://stackoverflow.com/search?q=geocoding

Good luck!

Community
  • 1
  • 1
QED
  • 9,803
  • 7
  • 50
  • 87
10

Swift version

        let location = self.txtLocation.text;
        let geocoder:CLGeocoder = CLGeocoder();
        geocoder.geocodeAddressString(location!) { (placemarks: [CLPlacemark]?, error: NSError?) -> Void in
            if placemarks?.count > 0 {
                let topResult:CLPlacemark = placemarks![0];
                let placemark: MKPlacemark = MKPlacemark(placemark: topResult);

                var region: MKCoordinateRegion = self.mkMapView.region;
                region.center = (placemark.location?.coordinate)!;
                region.span.longitudeDelta /= 8.0;
                region.span.latitudeDelta /= 8.0;
                self.mkMapView.setRegion(region, animated: true);
                self.mkMapView.addAnnotation(placemark);

            }
        }
Deepak Thakur
  • 3,453
  • 2
  • 37
  • 65
7

Since iOS 7, placemark.region.center is deprecated. Now needs to use:

region.center = [(CLCircularRegion *)placemark.region center];

You can also read Apple Documentation about this and here too.

Community
  • 1
  • 1
EEduard
  • 173
  • 1
  • 2
  • 8
6

Here's another version ...

- Swift 2017 syntax

- Shows a placename for the point, down the bottom

- Choose any size, say 5 km, as the area shown

func map() {
    let 5km:CLLocationDistance = 5000
    
    let a= "100 smith avenue some town 90210 SD"
    let g = CLGeocoder()
    
    g.geocodeAddressString(a) { [weak self] placemarks, error in
        if let p = placemarks?.first, let l = placemark.location {
            
            let p = MKPlacemark(coordinate: l.coordinate, addressDictionary: nil)
            
            let cr = MKCoordinateRegionMakeWithDistance(l.coordinate, 5km, 5km)
            let options = [
                MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: cr.center),
                MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: cr.span)
            ]
            
            let m = MKMapItem(placemark: p)
            m.name = "Your House"
            m.openInMaps(launchOptions: options)
        }
    }


}
Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
1

That is not possible. But you can obtain the long/lat from an Address by using the CLGeocoder class.

yinkou
  • 5,756
  • 2
  • 24
  • 40