iOS - MKMapView place annotation by using address instead of lat / long
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];
}
}
];
Show address in annotation when pin is dropped on map
First, in the addPinToMap:
method, addressLocation
is called with currentLocation
but currentLocation
is never set. It's declared a few lines up but not set to any value.
So change:
CLLocation *currentLocation;
to:
CLLocation *currentLocation = [[CLLocation alloc]
initWithLatitude:touchMapCoordinate.latitude
longitude:touchMapCoordinate.longitude];
Second, even with this fix, it still won't work. The annotation's title
will not get set because the reverseGeocodeLocation
method's completion handler block will finish after the annotation has already been added (the block is asynchronous -- the code in addPinToMap:
will not wait for it to finish).
You'll need to change the code around a bit and add the annotation inside the completion block when you actually have the geocoder result (whether success or failure).
Move the reverseGeocodeLocation
call to the addPinToMap:
method:
CLLocation *currentLocation = [[CLLocation alloc]
initWithLatitude:touchMapCoordinate.latitude
longitude:touchMapCoordinate.longitude];
[self.geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemark, NSError *error) {
//initialize the title to "unknown" in case geocode has failed...
NSString *annTitle = @"Address unknown";
//set the title if we got any placemarks...
if (placemark.count > 0)
{
CLPlacemark *topResult = [placemark objectAtIndex:0];
annTitle = [NSString stringWithFormat:@"%@ %@ %@ %@", topResult.country, topResult.locality, topResult.subLocality, topResult.thoroughfare];
}
//now create the annotation...
MapAnnotation *toAdd = [[MapAnnotation alloc]init];
toAdd.coordinate = touchMapCoordinate;
toAdd.title = annTitle;
toAdd.subtitle = @"Subtitle";
[self.map addAnnotation:toAdd];
}];
Mapkit, how to change annotation coordinates to nearest address?
I would just use a reverse geocode here returning an MKPlacemark. The documentation suggests that normally just one placemark will be returned by the completion handler, on the main thread, so you can use the result straightaway to update the UI. MKPlacemark conforms to the annotation protocol so you can put it directly on the map:
func resolveAddress(for averageCoordinate: CLLocationCoordinate2D, completion: @escaping (MKPlacemark?) -> () ) {
let geocoder = CLGeocoder()
let averageLocation = CLLocation(latitude: averageCoordinate.latitude, longitude: averageCoordinate.longitude)
geocoder.reverseGeocodeLocation(averageLocation) { (placemarks, error) in
guard error == nil,
let placemark = placemarks?.first
else {
completion(nil)
return
}
completion(MKPlacemark(placemark: placemark))
}
}
@IBAction func middleFinderButton(_ sender: Any) {
// your code to find center annotation
resolveAddress(for: centerPoint.coordinate) { placemark in
if let placemark = placemark {
self.mapView.addAnnotation(placemark)
} else {
self.mapView.addAnnotation(centerCoordinate)
}
}
Setting the title and subtitle on a Map Annotation view
Use MKPointAnnotation
instead.
Sample Code :
CLPlacemark *topresult = [placemarks objectAtIndex:0];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = topresult.location.coordinate;
annotation.title = self.business.businessName;
annotation.subtitle = self.business.phoneNumber;
[self.mapView addAnnotation:annotation];
How can i get any information like lat,long when i touch on MKMapView in iPhone/iPad?
With iOS 3.2 or greater, it's probably better and simpler to use a UIGestureRecognizer
with the map view instead of trying to subclass it and intercepting touches manually.
First, add the gesture recognizer to the map view:
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(tapGestureHandler:)];
tgr.delegate = self; //also add <UIGestureRecognizerDelegate> to @interface
[mapView addGestureRecognizer:tgr];
[tgr release];
Next, implement shouldRecognizeSimultaneouslyWithGestureRecognizer
and return YES
so your tap gesture recognizer can work at the same time as the map's (otherwise taps on pins won't get handled automatically by the map):
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer
:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
Finally, implement the gesture handler:
- (void)tapGestureHandler:(UITapGestureRecognizer *)tgr
{
CGPoint touchPoint = [tgr locationInView:mapView];
CLLocationCoordinate2D touchMapCoordinate
= [mapView convertPoint:touchPoint toCoordinateFromView:mapView];
NSLog(@"tapGestureHandler: touchMapCoordinate = %f,%f",
touchMapCoordinate.latitude, touchMapCoordinate.longitude);
}
MKMapview place pin at location (long/lat)
Find the below very simple solution to drop the pin at given location define by CLLocationCoordinate2D
Drop Pin on MKMapView
Edited:
CLLocationCoordinate2D ctrpoint;
ctrpoint.latitude = 53.58448;
ctrpoint.longitude =-8.93772;
AddressAnnotation *addAnnotation = [[AddressAnnotation alloc] initWithCoordinate:ctrpoint];
[mapview addAnnotation:addAnnotation];
[addAnnotation release];
Plotting a Specific Location on map view with latitude and longitude
For the "previous one also remains on the screen" problem: don't keep making a new annotation and calling addAnnotation
if you don't want to keep adding new annotations. Instead, keep hold of the annotation that you add, and move it later using its coordinate property. Something like this maybe:
class ViewController: UIViewController, MKMapViewDelegate {
@IBOutlet weak var mapView: MKMapView!
var annotationForThing: MKPointAnnotation?
var coordinateOfThing: CLLocationCoordinate2D? {
didSet {
guard let newCoord = coordinateOfThing else {
if let existing = annotationForThing {
mapView.removeAnnotation(existing)
}
return
}
if let existing = annotationForThing {
existing.coordinate = coordinateOfThing
}
else {
let newAnnotation = MKPointAnnotation()
newAnnotation = coordinateOfThing
mapView.addAnnotation(newAnnotation)
annotationForThing = newAnnotation
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self // or connect in storyboard
}
Related Topics
Uitableview - Scroll to the Top
How to Update a Localized Storyboard's Strings
Difference Between Dispatchqueue.Main.Async and Dispatchqueue.Main.Sync
How to Style Uitextview to Like Rounded Rect Text Field
Implement Pushkit and Test in Development Behavior
How to Put an Image in a Realm Database
Building for iOS Simulator, But the Linked Framework '****.Framework' Was Built for iOS
Ibeacon Notification When the App Is Not Running
How to Store an Image in Core Data
iOS 7 Status Bar Collides with Navigationbar
Get Device Location (Only Country) in iOS
How to Create a Colored 1X1 Uiimage on the iPhone Dynamically
How to Update a Coredata Entry That Has Already Been Saved in Swift
How to Mask a Square Image into an Image with Round Corners in iOS