Why didn't my map annotation move? - iphone

I am implementing a mapView whereby an annotation will be placed when the user search for an address. But somehow, the annotation sometime doesn't move and update to the new coordinate. It's only upon zooming the map, then will it update to the new location. The subtitle did get updated though.
- (void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar {
SVGeocoder *geocodeRequest = [[SVGeocoder alloc] initWithAddress:searchBar.text inRegion:#"sg"];
[geocodeRequest setDelegate:self];
[geocodeRequest startAsynchronous];
}
- (void)geocoder:(SVGeocoder *)geocoder didFindPlacemark:(SVPlacemark *)placemark {
if (annotation) {
[annotation moveAnnotation:placemark.coordinate];
annotation.subtitle = [NSString
stringWithFormat:#"%#", placemark.formattedAddress];
}
else {
annotation = [[MyAnnotation alloc]
initWithCoordinate:placemark.coordinate
title:#"Tap arrow to use address"
subtitle:[NSString
stringWithFormat:#"%#", placemark.formattedAddress]];
[mapView addAnnotation:annotation];
}
MKCoordinateSpan span;
span.latitudeDelta = .001;
span.longitudeDelta = .001;
MKCoordinateRegion region;
region.center = placemark.coordinate;
region.span = span;
[mapView setRegion:region animated:TRUE];
[searchBar resignFirstResponder];
}

I don't think MKMapView gets notified of changes to an annotation's location. The documentation of MKAnnotation's setCoordinate: says: "Annotations that support dragging should implement this method to update the position of the annotation." so it seems that's the only purpose of this method is for supporting dragging of pins.
Try removing the annotation from the map view before changing its coordinates and then add it back to the map view.

Nothing in your code (that you've shown) tells mapView that the annotation's location has changed. The annotation itself probably can't do it in -moveAnnotation because annotations generally don't know what map or maps they've been added to (nor should they).
The right way to move an annotation is to to remove it from the MKMapView that's using it, update its location, and then add it back to the map. You can't just change the annotation's location after it has been added to the map because the map may very well cache the location or sort the annotation according to its location, and there's no method in MKMapView to tell the map that the location has changed.
I'd change your conditional to something like this:
if (annotation == nil) {
annotation = [[MyAnnotation alloc] init];
annotation.title = #"Tap arrow to use address";
}
[mapView removeAnnotation:annotation];
[annotation moveAnnotation:placemark.coordinate];
annotation.subtitle = placemark.formattedAddress;
[mapView addAnnotation:annotation];
This assumes that it's safe to call -init in place of -initWithCoordinate:title:subtitle:; if not, you'll want to change that.

Related

Centering MKMapView on an annotation

Although the process for doing this is well documented, I am unable to solve this problem.
All I want to do is to take the coordinate at which I have just created an annotation and have the map zoom in and center on it. I followed this tutorial with some modifications:
http://maybelost.com/2011/01/a-basic-mapview-and-annotation-tutorial/
The MapViewAnnotation class consists of just a title and the coordinates.
_detailItem is simply an object that holds a name, latitude, and longitude as strings.
I have a basic map. I'm using a storyboard (so, ARC). I have coordinates. Here's my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
// Set some coordinates for our position
CLLocationCoordinate2D location;
double thisLat = [_detailItem.EventLat doubleValue];
double thisLong = [_detailItem.EventLong doubleValue];
location.latitude = (double)thisLat;
location.longitude = (double)thisLong;
// Add the annotation to our map view
MapViewAnnotation *newAnnotation = [[MapViewAnnotation alloc] initWithTitle:_detailItem.EventName andCoordinate:location];
[self.map addAnnotation:newAnnotation];
}
// When a map annotation point is added, zoom to it
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *annotationView = [views objectAtIndex:0];
id <MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 1000, 1000);
[mv setRegion:region animated:YES];
[mv selectAnnotation:mp animated:YES];
}
Yeah. When I do this, the annotations shows up as expected, but the map doesn't center on it or zoom in. During debug, I found that didAddAnnotationViews isn't being called at all! Yet, I've clearly made an explicit call to addAnnotation.
Help?
didAddAnnotationViews isn't being called at all
In your viewDidLoad implementation, add this line:
self.map.delegate = self;
See if that changes things.

Crashed while removing the pin from mapview

I am working on MapView,on which I have two buttons.
1)centreButton:
this button drops the pin annotation at the centre of the current map.
when this button is pressed, I am storing the last annotation in a NSMutable array.
then remove the last annotation from mapview and drop one pin at the centre of map
Code I have done for this part is as follows:
function for dropping the pin
- (void)PinDropwithlatitude:(double)lat longitude:(double)longi droptitle:(NSString *)title
{
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = lat;
theCoordinate.longitude = longi;
MKCoordinateRegion region;
region.center.latitude = theCoordinate.latitude;
region.center.longitude = theCoordinate.longitude;
//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta =0.005;
span.longitudeDelta =0.005;
region.span = span;
[MapView setRegion:region animated:YES];
SetLat =lat;
SetLong =longi;
DDAnnotation *annotation = [[[DDAnnotation alloc] initWithCoordinate:theCoordinate addressDictionary:nil] autorelease];
annotation.title = title;
annotation.subtitle = [NSString stringWithFormat:#"%f %f", annotation.coordinate.latitude, annotation.coordinate.longitude];
[MapView addAnnotation:annotation];
}
when I press centre button I am doing the following code and store last array in annotation.
-(IBAction)CenterPressed:(id)sender
{
//40.439631,-3.698273 -spain centre
[lastAnnotation addObjectsFromArray:MapView.annotations];
NSLog(#"last annotation array=%#",lastAnnotation);
for (id annotation in [MapView annotations])
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
continue;
}
[MapView removeAnnotation:annotation];
}
[self PinDropwithlatitude:SetLat longitude:SetLong
droptitle:NSLocalizedString(#"Title", nil)];
}
the log for the array is showing me the
last annotations you can see below::
last annotation array=(
"<+40.43963100,-3.69827300> +/- 0.00m",
"<+40.43923187,-3.68722200> +/- 0.00m",
"<+40.43792343,-3.67670774> +/- 0.00m",
"<+40.43772888,-3.66711617> +/- 0.00m"
)
2)UNDOButton: which removes the currently placed annotation and redrop the previous annotation, for that i have removed the annotaion from mapview, and redrop the annotation last annotation from array which i have maintained previously,using the code:
-(IBAction)undoPressed:(id)sender
{
if ([lastAnnotation count]>0)
{
int countAnn = [lastAnnotation count];
[MapView removeAnnotation:[lastAnnotation objectAtIndex:countAnn-1]];
//[MapView delete:[lastAnnotation objectAtIndex:countAnn-1]];
[lastAnnotation removeObjectAtIndex:countAnn-1];
double latitude = [[[lastAnnotation objectAtIndex:[lastAnnotation count]-1] annotation]coordinate].latitude;
double longitude = [[[lastAnnotation objectAtIndex:[lastAnnotation count]-1]annotation]coordinate].longitude;
NSLog(#"count = %d",[lastAnnotation count]);
[self PinDropwithlatitude:latitude longitude:longitude droptitle:NSLocalizedString(#"Title", nil)];
}
}
but when i press the undo button it crashes with the following error
-[DDAnnotation annotation]: unrecognized selector sent to instance 0x79b8f40
I don't get to know, where exactly the problem arises. can any one please help me to point out my mistake in the above code.
thanks
can you try
[lastAnnotation lastObject]
instead of
[[lastAnnotation objectAtIndex:[lastAnnotation count]-1]
like
[MapView removeAnnotation:[lastAnnotation lastObject]];
[lastAnnotation removeObject:[lastAnnotation lastObject]];

Smooth Movement of annotation image on Mapview

I have loaded the custom annotation image for user current location.I am updating the current user location after every 1 sec in background.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self performSelectorOnMainThread:#selector(tempupdate) withObject:nil waitUntilDone:NO];
[pool release];
-(void)tempupdate
{
NSLog(#"callToLocationManager");
mylocationManager = [[CLLocationManager alloc]init];
NSLog(#"locationManagerM = %#",mylocationManager);
mylocationManager.delegate = self;
mylocationManager.desiredAccuracy = kCLLocationAccuracyBest;
mylocationManager.distanceFilter = 500;
[mylocationManager startUpdatingLocation];
}
After updating the current latutude and longitude i am refreshing the map using following code
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta=0.002;
span.longitudeDelta=0.002;
CLLocationCoordinate2D location;
location.latitude=[lat doubleValue];
location.longitude=[longt doubleValue];
region.span=span;
region.center=location;
addAnnotation=[[AddressAnnotation alloc]initWithCoordinate:location];
addAnnotation.mTitle=#"You are here";
[self.mapView removeAnnotations:self.mapView.annotations];
[self.mapView addAnnotation:addAnnotation];
[self.mapView setRegion:region animated:TRUE];
[self.mapView regionThatFits:region];
But every time custom annotation image blinks before adding to the map.How to avoid this flicker effect?
I haven't tested this yet, but based on a quick glance at your code, I would guess the issue lies in your removal of the annotation and then adding a new one.
Have you tried just editing the already attached annotation's properties?
NSArray* curAnnotations = [mapView annotations];
AddressAnnotation* aa = [curAnnotations lastObject]; // I am assuming you only have 1 annotation
aa.mTitle = #"You are here"; // or don't do this if it never changes
[aa setCoordinate:location];
Note: Apple Docs specifically call out the 'setCoordinate' method as something that should be used to support dragging or frequent updates.
you mustn't remove annotation from map. Instead change the annotation coordinate in the UIView beginAnimations-commitAnimations block;
It will look something like this:
[UIView beginAnimations:#"yourAnimationName" context:nil];
[UIView setAnimationDuration:1.0];
[yourAnnotation setCoordinate:yourNewCoordinate];
[UIView commitAnimations];
It will move smoothly the annotation.
BR,
Marcin Szulc
//SWIFT 3
UIView.beginAnimations("yourname", context: nil)
UIView.setAnimationDuration(1.0)
yourpin.coordinate = MKCoordinateForMapPoint(mycoordinate)
UIView.commitAnimations()

iOS Core Location Set Pin to user location in viewDidLoad

I am attempting to set a map annotation to the user's current location. I am trying to set the pin in the viewDidLoad method, however because the method
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
Has not been called yet, the lat and long are 0.000000. Is there a way to call this method in my viewDidLoad or any other solution that will make a pin appear at my beginning location when the application loads?
UPDATE, Added Annotation Code
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = (_currentLocation.latitude);
theCoordinate.longitude = (_currentLocation.longitude);
NSLog(#"The Coordinate Value:");
NSLog(#"%f, %f",theCoordinate.latitude,theCoordinate.longitude);
DDAnnotation *annotation = [[[DDAnnotation alloc] initWithCoordinate:theCoordinate addressDictionary:nil] autorelease];
annotation.title = #"Drag to Move Pin";
annotation.subtitle = [NSString stringWithFormat:#"%f %f", annotation.coordinate.latitude, annotation.coordinate.longitude];
[self.mapView addAnnotation:annotation];
UPDATE 2
Still not working, code is in the didUpdateLocation Method
static BOOL annotationAdded = NO;
if (!annotationAdded) {
annotationAdded = YES;
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = _currentLocation.latitude;
theCoordinate.longitude = _currentLocation.longitude;
//Sets Initial Point to Africa Because Method to obtain current Location
//Hasen't Fired when View Loads
theCoordinate.latitude = (mapView.userLocation.coordinate.latitude);
theCoordinate.longitude = (mapView.userLocation.coordinate.longitude);
NSLog(#"The Coordinate Value:");
NSLog(#"%f, %f",theCoordinate.latitude,theCoordinate.longitude);
DDAnnotation *annotation = [[[DDAnnotation alloc] initWithCoordinate:theCoordinate addressDictionary:nil] autorelease];
annotation.title = #"Drag to Move Pin";
annotation.subtitle = [NSString stringWithFormat:#"%f %f", annotation.coordinate.latitude, annotation.coordinate.longitude];
[self.mapView addAnnotation:annotation];
}
MKMapView automatically places an annotation of class MKUserLocation when you set mapView.showsUserLocation = YES.
You can replace the default view for this annotation to whatever default annotation view you want by doing this in mapView:viewForAnnotation::
- (MKAnnotationView *) mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
// replace the following with code to generate and return custom user position annotation view
return customAnnotationView;
}
//*** other code ***//
}
Update:
If all you want to do is set a pin initially (once) at the user's location when the view loads, then you will have to wait until the phone can grab the data you need since that takes some time. Add your annotation in mapView:didUpdateUserLocation the first time it is called, and that should do the trick:
- (void) mapView:(MKMapView *)theMapView didUpdateUserLocation:(MKUserLocation *)userLocation {
static BOOL annotationAdded = NO;
if (!annotationAdded) {
annotationAdded = YES;
//*** add annotation to mapView ***//
}
}
Final Comment:
I would generally avoid setting a static pin at a users location the first time this method is called, however, and instead opt to just using the default standard blue dot. That is because the location services in the phone take time to find an accurate reading on the user's location, but in the interest of time it will send you location updates as soon as possible. This means that the first location update may not be very accurate, but subsequent updates may be much more accurate. That is why the standard blue dot sometimes changes position frequently within the first few moments of showing up on the map.
Just a caveat. Obviously what you choose to do depends on what the purpose of your app is.
I've never found a way to manually call that method. I believe it's a delegate method that's completely passive. Sorry.
It takes some time for the device to determine the location -- you can't speed up the process by calling -locationManager:didUpdateToLocation: yourself. You'll need to either use #Matt's suggestion to let the map draw the user's location, or else wait for -...didUpdateToLocation: to be called and take action then.

didAddAnnotationViews not getting called always

I added a MKAnnotation delegate handler class into a MKMapView like this.
MapAnnotation *anAnnotation = [[[MapAnnotation alloc] initWithCoordinate:coord] autorelease];
[myMapView addAnnotation:anAnnotation];
The MapAnnotation implements the MKAnnotation.
However didAddAnnotationViews doesnt get called always. Sometimes (rarely) it does and sometimes its not. I checked few places and I have used this correctly. Does it depends on span attributes as well?
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta=0.005f;
span.longitudeDelta=0.005f;
CLLocationCoordinate2D location;
location.latitude = searchLocation.coordinate.latitude;
location.longitude = searchLocation.coordinate.longitude;
region.span=span;
region.center=location;
[myMapView setRegion:region animated:TRUE];
[myMapView regionThatFits:region];
Whats wrong with this code?
This delegate method is called for annotations that are currently visible i.e. those that are within the map region that is currently displayed on the screen.