Within my app we have a screen with an MKMapView.
This map shows pins for a bunch of Locations (location is a model defined within the app).
When running in the simulator this works fine. However, when running this on a device the pins seem to disappear and re-appear almost each time the map is panned. Even slight touches and movements can cause the map to show and hide pins.
The map isn't particularly busy, even when showing one pin it will show and hide it.
Has anybody any idea why this might be happening? I've pasted my code below... It's a Rubymotion app so the code is in Ruby.
I've added the Objective C equivalent to this Ruby code below. Apologies if there are a couple of typos or idiomatic errors, it's been a while since I've written any OC.
Watching the logger, I can see that mapView:viewForAnnotation
is being called each time a map pin disappears/reappears.
Also each time mapView:regionDidChangeAnimated
I can see that the Object IDs for the annotations are the same - so I don't think they're being removed (which they shouldn't be)
# ====================
# = MKMapKitDelegate =
# ====================
# Don't react if the user has moved less than three meters
USER_MOVE_THRESHOLD = 3
# The user location has changed
def mapView(mapView, didUpdateUserLocation: newLocation)
NSLog("mapView:didUpdateUserLocation")
return unless userLocation
coord = newLocation.coordinate
newLocationAsCL = CLLocation.alloc.initWithCoordinate(coord, altitude: 1, horizontalAccuracy:1, verticalAccuracy: -1, timestamp: nil)
meters = newLocationAsCL.distanceFromLocation(@lastUserCLLocation)
# If user has moved less than 3m, return
if meters > 0 and meters < USER_MOVE_THRESHOLD
log "Distance was less than #{USER_MOVE_THRESHOLD} meters (#{meters}) - returning ***"
return
end
# If the coord is the same as the previous user location
if userLocation.coordinate.latitude == coord.latitude && userLocation.coordinate.longitude == coord.longitude
log "User hasn't moved - returning ***"
else
log 'User has moved'
end
log "Did update user location: #{coord.latitude},#{coord.longitude}"
if coord.latitude.to_f == 0.0 and coord.longitude.to_f == 0.0
log 'Invalid coordinate received - returning ***'
else
fetchLocationsFromAPI
end
end
def mapView(mapView, regionDidChangeAnimated: animated)
NSLog("mapView:regionDidChangeAnimated:#{animated}")
# do nothing here yet...
end
# create map pins...
def mapView(mapView, viewForAnnotation: annotation)
log "mapView:viewForAnnotation: #{annotation.inspect}"
if annotation.is_a?(Location)
# If there's already an annotation we can use, use it! Otherwise create a new one
annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.class.to_s) || begin
annotationView = MKPinAnnotationView.alloc.initWithAnnotation(annotation, reuseIdentifier: annotation.class.to_s)
annotationView.enabled = true
annotationView.canShowCallout = true
annotationView.animatesDrop = false
annotationView.pinColor = MKPinAnnotationColorRed
rightButton = UIButton.buttonWithType(UIButtonTypeDetailDisclosure)
rightButton.addTarget(self, action: 'showLocationScreen:', forControlEvents: UIControlEventTouchUpInside)
annotationView.rightCalloutAccessoryView = rightButton
annotationView
end
annotationView.annotation = annotation
annotationView.rightCalloutAccessoryView.tag = @mapLocations.index(annotation)
return annotationView
end
end
def mapView(mapViewm, didAddAnnotationViews: views)
NSLog("mapView:didAddAnnotationViews - #{views}")
# do nothing here yet...
end
#define kUserMoveThreshold 1
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)newLocation
{
NSLog(@"mapView:didUpdateUserLocation")
if (!userLocation) {
return;
}
CLLocationCoordinate2D coord = newLocation.coordinate;
CLLocation newLocationAsCL = [[CLLocation alloc] initWithCoordinate: coord altitude: 1 horizontalAccuracy: 1 verticalAccuracy: -1 timestamp: NULL];
CLLocationDistance meters = [newLocationAsCL distanceFromLocation: lastUserCLLocation];
// If user has moved less than 3m, return
if (meters > 0 && meters < kUserMoveThreshold){
NSLog(@"Distance was less than %d meters (%d) - returning ***", kUserMoveThreshold, meters);
return;
}
// If the coord is the same as the previous user location
if (userLocation.coordinate.latitude == coord.latitude && userLocation.coordinate.longitude == coord.longitude){
NSLog(@"User hasn't moved - returning ***");
return;
} else {
NSLog(@"User has moved");
}
NSLog(@"Did update user location: %f,%f", coord.latitude, coord.longitude);
if (coord.latitude == 0.0 && coord.longitude == 0.0){
NSLog(@"Invalid coordinate received - returning ***");
} else {
[self fetchLocationsFromAPI];
}
}
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSLog(@"mapView:regionDidChangeAnimated: %s", animated ? @"TRUE" : @"FALSE");
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
{
NSLog(@"mapView:viewForAnnotation %s", annotation.description);
if ([annotation isKindOfClass: [Location class]]){
// If there's already an annotation we can use, use it! Otherwise create a new one
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier: [annotation className]];
if (!annotationView){
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation: annotation reuseIdentifier: [annotation className]];
[annotationView setEnabled: YES];
[annotationView setCanShowCallout: YES];
[annotationView setAnimatesDrop: NO];
[annotationView setPinColor: MKPinAnnotationColorRed];
UIButton *rightButton = [UIButton buttonWithType: UIButtonTypeDetailDisclosure];
[rightButton addTarget: self action: @selector(showLocationScreen:) forControlEvents: UIControlEventTouchUpInside];
[annotationView setRightCalloutAccessoryView: rightButton];
}
[annotationView annotation: annotation];
[[annotationView rightCalloutAccessoryView] setTag: [mapLocations indexOfObject: annotation]];
return annotationView
}
}
-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
NSLog(@"mapView:didAddAnnotationViews %@", views)
}
This was a bug with Rubymotion which seems to have been addressed in version 1.30
= RubyMotion 1.30 =
...
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With