MKAnnotationView is not getting displayed in iOS 11 - annotations

I am having an application running on app store, which has map view with other functionality.
Everything works perfectly till iOS 10 (all versions except iOS 11), now when I tested same app on iOS 11, then MKAnnotationView is not getting displayed (This happens only with iOS 11).
There is no any exception/error shown.
I went thought apple documentation, but there is no any such deprecation in API's, but still its not working.
Can someone please help me out in this issue.

I was able to get it to display by calling "prepareForDisplay" on the annotation view within the viewForAnnotation delegate method. prepareForDisplay is a new method in iOS 11, but it is not documented.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
// Current Location Annotation
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
// Custom Annotation
if ([annotation isKindOfClass:[CustomAnnotationView class]]) {
CustomAnnotationView *view = (CustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"Custom"];
if (!view) {
view = [[CustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"Custom"];
} else {
view.annotation = annotation;
}
if (#available(iOS 11.0, *)) {
[view prepareForDisplay];
}
return view;
}
return nil;
}
I'm still trying to figure out if this is a bug or proper use. Stay tuned!

Related

MKUserLocation blue userLocation MKAnnotation causes app to crash if inadvertently touched

I have a MKMap with a series of MKAnnotations, all of which are red which is fine. I have selected "show user location" in IB and to change the MKAnnotation from red to blue, I have the code in my viewForAnnotation method:
if (annotation == theMap.userLocation)
return nil;
All is good and the app works fine, but if the user inadvertently taps the blue userlocation dot I get the following crash:
2012-02-01 20:43:47.527 AusReefNSW[27178:11603] -[MKUserLocationView setPinColor:]: unrecognized selector sent to instance 0x79b0720
2012-02-01 20:43:47.528 AusReefNSW[27178:11603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MKUserLocationView setPinColor:]: unrecognized selector sent to instance 0x79b0720'
*** First throw call stack:
If I remove the above code, all works well but the pin is red. I perfer to have the blue icon but as yet have not discovered why the crash. Any ideas would be appreciated. Thanks.
SOLVED! Thanks Marvin and heres the code incase anyone finds it useful. In a nutshell, I had to first check to see if the MKAnnotation was of MyAnnotation Class or of MKUserLocation Class.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKPinAnnotationView *)view
{
theAnnotationSelected = [[mapView selectedAnnotations] objectAtIndex:0];
if ([theAnnotationSelected isKindOfClass:[MyAnnotation class]] )
{
view.pinColor = MKPinAnnotationColorGreen;
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKPinAnnotationView *)view
{
if ([theAnnotationSelected isKindOfClass:[MyAnnotation class]] )
{
view.pinColor = MKPinAnnotationColorRed;
}
For Current User Location go to MKMapView property and make selection on Shows User Location in XIB.
then Implement MKMapViewDelegate in your controller..and write this method in your controller
-(MKAnnotationView *)mapView:(MKMapView *)pmapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil; //return nil to use default blue dot view
if([annotation isKindOfClass:[MKAnnotationClass class]])
{
//Your code
}
}
and this
- (void)mapView:(MKMapView *)mapView1 didSelectAnnotationView:(MKAnnotationView *)customAnnotationView
{
if(![annotation isKindOfClass:[MKUserLocation class]])
{
//Your code
}
}
Using this you can see blue dot on User Location..
You will want to check the class of the annotation in
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
Then do the following..
id *annotation = view.annotation;
if (![annotation isKindOfClass:[MKUserLocation class]]) {
//Normal Code here
}
This solution works in iOS7 to suppress the callout view, but it does not stop the user from selecting the blue dot. How to suppress the "Current Location" callout in map view
I have yet to find a way to disable selection of the current location dot.
It isn't so much a workaround as a "way to deal with it", but I zoom the map in to focus on certain types of annotations when tapped. If the user happens to be located right on top of one, the zooming helps put some distance between the blue dot and my annotation, making it easier to tap.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
if([view.annotation isKindOfClass:[SpecialClass class]]){
SpecialClass *cluster = (SpecialClass *)view.annotation;
if(testCriteria){
[self.mapView setRegion:MKCoordinateRegionMakeWithDistance(cluster.coordinate, cluster.radius, cluster.radius) animated:YES];
}
}
I had the same issue such that when a user would tap the MKUserlocation "blue dot" the application would crash. I am using DDAnnotation by Ching-Lan 'digdog' HUANG. The fix I found was
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
id annotation = view.annotation;
if (![annotation isKindOfClass:[MKUserLocation class]]) {
//Your Annotation Code here
}
}

How to create a callout bubble MKAnnotationView that respond to touches

I'm trying to make a custom annotation view able to respond to touches without success.
Thanks to this question I was able to made an annotation view close to what I want customize callout bubble for annotationview? also seen this How to capture touches and NOT dismiss the callout? but the problem is quite different
The first thing I've done so far is subclassing an MKAnnotationView and override the -setSelected:animated: method
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if(selected)
{
MyCallOut * callOut=[MyCallOut createMyCallOut];
callOut.tag=555;
[self.superview addSubview:callOut];
}
else
{
// [[self viewWithTag:555] removeFromSuperview];
//Remove my custom CallOut
}
}
The problem is that the map view is eating all the touches event, my custom callout has two buttons but no action is triggered pressing them.
In one of my experiment I've tried to add the callout view to the MKAnnotationView superview (the mapView) everything seems to be fine while I scroll, but If I zoom the callout moves around.
you have to add call out accessory view in map annotation
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil ) pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return pinView;
}
else {
[mapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
and for click event of your call out
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
}
Solved looking to this link Custom annotation and callouts, the other tricky part is implement a correct way to press button on the fake callout. I managed this part creating a boolean value that understands the number of annotation/parentAnnotation on screen and choose when one could disappear or not.Just need to make the CalloutAnnotation available to selection.

Custom annotation pin changes to default red pin at long tap

I have custom annotation pin at app:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
return [kml viewForAnnotation:annotation type:state];
}
where I return custom view and make setImage for annotationView of Placemark such as:
- (MKAnnotationView *)viewForAnnotation:(id <MKAnnotation>)point type:(int)state
{
// Find the KMLPlacemark object that owns this point and get
// the view from it.
for (KMLPlacemark *placemark in _placemarks) {
if ([placemark point] == point)
{
UIButton *disclosureButton = [UIButton buttonWithType: UIButtonTypeDetailDisclosure];
[[placemark annotationView] setCanShowCallout: YES];
[[placemark annotationView] setRightCalloutAccessoryView:disclosureButton];
if (state == 0)
{
[[placemark annotationView] setImage:[UIImage imageNamed:#"ic_pin_tour.png"]];
}
else
{
[[placemark annotationView] setImage:[UIImage imageNamed:#"ic_pin_point.png"]];
}
return [placemark annotationView];
}
}
return nil;
}
but if I long tap at my annotation pin it changes appearance to its default view (RedPin).
I cannot understand what method is called on long tap. I tried to play with UITapGestureRecognizer, but did not find out. If I just tap annotation pin all works fine and my custom annotation pin view doesn't disappear.
You can see what I mean in this screenshot:
So, why annotation pin appearance changes on long tap?
So, if you want to use a custom image for an annotation view, always use a generic MKAnnotationView instead of an MKPinAnnotationView.
I have MKPinAnnotationView at just one place, when I replace it with MKAnnotationView everything works properly now:
- (MKAnnotationView *)annotationView
{
if (!annotationView) {
id <MKAnnotation> annotation = [self point];
if (annotation) {
MKAnnotationView *pin =
[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
pin.canShowCallout = YES;
annotationView = pin;
}
}
return annotationView;
}

Problem placing a button inside a MKAnnotationView

I'm trying to put a little button in my AnnotationViews to show some info about some places on a map. Sounds super basic? Well. I must be an idiot then...
I've looked at multiple examples, searched the whole internet, and I have ripped of 95% of my hair. It just doesn't work!
-(MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)theAnnotation;
{
MKAnnotationView * annotationView = nil;
if([theAnnotation class] == [MyAnnotation class])
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:theAnnotation reuseIdentifier:#"annotation"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.enabled = YES;
}
return annotationView;
}
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control;
{
NSLog(#"push %#", control);
}
Can some one please tell me why calloutAccessoryControlTapped never gets called?
I get a nice and pretty annotation, but when I tap the blue button it just closes. I have tried adding a target to the button, nothing.
Please help me!
PS: I know I should reuse old annotation view and stuff, but i stripped all code that wasn't necessary to be sure that there wasn't something else that was screwing thins up.
Make sure you have correctly set the delegate responding to the MKMapViewDelegate Protocol.
Also, make sure that all the views and superviews have userInterActionEnabled set to YES.

In using the Mapkit, I can see the fully scrollable map however no Apple headquarters?

I have tried it both on an actual device (iPad) and the iPhone simulator (ios 4)
I see the map but no Apple headquarters (blue pin) even if I zoom in.
In my OnViewLoad function I have:
mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
mapView.showsUserLocation=TRUE;
mapView.mapType=MKMapTypeHybrid;
[self.view insertSubview:mapView atIndex:0];
In your -mapView:viewForAnnotation: method, return nil if the annotation is a userLocation object:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isMemberOfClass:[MKUserLocation class]]) {
return nil;
}
// your normal code
}
This is needed to make sure, the iOS default implementation is used to show the blue userLocation dot.