简体   繁体   English

viewForAnnotation中的EXC_BAD_ACCESS

[英]EXC_BAD_ACCESS in viewForAnnotation

I have the following code that gives me an EXC_BAD_ACCESS. 我有以下代码为我提供了EXC_BAD_ACCESS。

I have a map and I'm loading a circle image that represents the actual position in the map. 我有一张地图,正在加载一个圆圈图像,该图像表示地图中的实际位置。

Edit here is the full code 在这里编辑是完整的代码

#import "ComoLlegarViewController.h"
#import "MBProgressHUD.h"

/*#define COLOR_TEXTO_NORMAL          [UIColor colorWithRed:204.0f/255.0f green:204.0f/255.0f blue:204.0f/255.0f alpha:1.0f]*/
#define COLOR_TEXTO_NORMAL [UIColor darkGrayColor]
#define COLOR_TEXTO_SELECCIONADO    [UIColor colorWithRed:0.0f/255.0f green:10.0f/255.0f blue:100.0f/255.0f alpha:1.0f]


#define kTIENDA_UNAM_LATITUD    19.321066
#define kTIENDA_UNAM_LONGITUD   -99.176202

@interface ComoLlegarViewController ()

@property (strong, nonatomic) MKPointAnnotation *puntoTiendaUNAM;

// Metodo que crea un punto en el Mapa y apunta a la Tienda UNAM
- (void)dropPinUbicacionTiendaUNAM;
- (void)hacerZoomAlMapa;
@end


@implementation ComoLlegarViewController

@synthesize segmentedControl = _segmentedControl;
@synthesize mapa = _mapa;
@synthesize puntoTiendaUNAM = _puntoTiendaUNAM;

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
}

#pragma mark - View lifecycle

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];

    if (self) {

        [self.navigationController.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:COLOR_TEXTO_NORMAL, NSForegroundColorAttributeName, nil] forState:UIControlStateNormal];

        [self.navigationController.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:COLOR_TEXTO_SELECCIONADO, NSForegroundColorAttributeName, nil] forState:UIControlStateSelected];


        [self.navigationController.tabBarItem setSelectedImage:[[UIImage imageNamed:@"icono_mapas_activado.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];

    }
    return self;
}


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
    [super viewDidLoad];

    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor blackColor], NSForegroundColorAttributeName,
                                [UIColor grayColor], NSForegroundColorAttributeName,
                                [NSNumber numberWithFloat:0.1f], NSShadowAttributeName,
                                nil];

    [_segmentedControl setTitleTextAttributes:attributes forState:UIControlStateNormal];

    // No need to retain (just a local variable)
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
    hud.labelText = @"Localizando";
    hud.detailsLabelText = @"Tienda UNAM";
    [hud hide:YES afterDelay:0.7f];

    // localizamos el pin en el mapa en el background
    [self dropPinUbicacionTiendaUNAM];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidUnload
{
    [super viewDidUnload];

    _mapa = nil;
    _segmentedControl = nil;
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}


/**
 Metodo que se encarga de mostrar el pin en el mapa con la ubicacion de la tienda UNAM
 */

- (void)dropPinUbicacionTiendaUNAM
{    
    // Referencia al mapa de la clase
    MKMapView *myMapView = _mapa;

    // Creamos un pin
    if (! _puntoTiendaUNAM) {
        _puntoTiendaUNAM= [[MKPointAnnotation alloc] init];
    }

    _puntoTiendaUNAM.title = @"TU Tienda UNAM";
    _puntoTiendaUNAM.coordinate = CLLocationCoordinate2DMake(kTIENDA_UNAM_LATITUD, kTIENDA_UNAM_LONGITUD);
    _puntoTiendaUNAM.subtitle = @"Dalias s/n, Oxtopulco, 04510 Coyoacán";

    // Lo agregamos al mapa
    [myMapView addAnnotation:_puntoTiendaUNAM];
    [myMapView setCenterCoordinate:_puntoTiendaUNAM.coordinate animated:YES];

    // Zoom al mapa para mostrar solo la region donde esta el pin, con un span de 1000 mts de radio
    MKCoordinateRegion mapRegion;
    mapRegion.center = _puntoTiendaUNAM.coordinate;
    mapRegion.span = MKCoordinateSpanMake(0.01, 0.01);
    [myMapView setRegion:mapRegion animated: YES];
}

#pragma mark MKMapView Delegate

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    // Creamos la vista de punto a desplegar
    MKPinAnnotationView *pinView = nil;
    pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"pinTiendaUNAM"];

    if (! pinView) {

        pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"pinTiendaUNAM"];

        // Configuramos la vista del punto

        UIImage *img=[UIImage imageNamed:@"bolita_mapa.png"];

        UIImageView *pinImageView = [[UIImageView alloc] initWithImage:img];
        [pinImageView setUserInteractionEnabled:YES];

        // Agregamos un gesture Recognizer a la bolita
        UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hacerZoomAlMapa)];
        [tapGestureRecognizer setNumberOfTapsRequired:1];
        [tapGestureRecognizer setNumberOfTouchesRequired:1];
        [pinImageView addGestureRecognizer:tapGestureRecognizer];

        [pinView addSubview:pinImageView];
        [pinView setPinColor:MKPinAnnotationColorPurple];
        [pinView setAnimatesDrop:YES];
        [pinView setCanShowCallout:YES];
        [pinView setCalloutOffset:CGPointMake(-8.0f, 0.0f)];
        // [pinView setSelected:YES animated:YES];

        UIButton *botonBrujula = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        //UIButton *botonBrujula = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];        
        //[botonBrujula setImage:[UIImage imageNamed:@"icono_mapa.png"] forState:UIControlStateNormal];
        //[botonBrujula addTarget:self action:@selector(hacerZoomAlMapa) forControlEvents:UIControlEventTouchUpInside];
        // [botonBrujula addTarget:self action:@selector(verInfo) forControlEvents:UIControlEventTouchUpInside];
        [pinView setRightCalloutAccessoryView:botonBrujula];


        // Agregamos el logo de tienda unam a la vista del punto
        UIImage *image = [UIImage imageNamed:@"logo_tienda_unam.png"];
//        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];

        UIButton *botonLogoTiendaUNAM = [UIButton buttonWithType:UIButtonTypeCustom];
        [botonLogoTiendaUNAM setFrame:CGRectMake(0, 0, 30, 30)];
        [botonLogoTiendaUNAM setBackgroundImage:image forState:UIControlStateNormal];

//        // Agregamos un gesture Recognizer al logo de tienda unam
//        UITapGestureRecognizer *tapGestureRecognizer_logo = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hacerZoomAlMapa)];
//        [tapGestureRecognizer_logo setNumberOfTapsRequired:1];
//        [tapGestureRecognizer_logo setNumberOfTouchesRequired:1];
//        [imageView addGestureRecognizer:tapGestureRecognizer_logo];

//        [pinView setLeftCalloutAccessoryView:imageView];
        [pinView setLeftCalloutAccessoryView:botonLogoTiendaUNAM];


 //Problema con la vista , entra en recursividad y se desborda el programa , corregir la annotation

        // Seleccionamos el pin para mostrar la informacion de 
    // [mapView selectAnnotation:annotation animated:YES];

        // Establecemos un tag a los callout views para diferenciarlos
        [[pinView rightCalloutAccessoryView] setTag:1];     // Ver Info
        [[pinView leftCalloutAccessoryView] setTag:2];      // Hacer Zoom

    } else {

        pinView.annotation = annotation;

    }


    pinView.annotation=annotation;
    return pinView;
}





- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{

[mapView selectAnnotation:self.puntoTiendaUNAM animated:YES];


}





- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    if ([control tag] == 1) {
        [self performSegueWithIdentifier:@"ver_info" sender:self];

    } else if ([control tag] == 2) {
        [self hacerZoomAlMapa];
    }
}


- (void)hacerZoomAlMapa
{
    [_mapa deselectAnnotation:_puntoTiendaUNAM animated:NO];

    // Zoom al mapa para mostrar solo la region donde esta el pin, con un span de 1000 mts de radio
    MKCoordinateRegion mapRegion;
    mapRegion.center = _puntoTiendaUNAM.coordinate;
    mapRegion.span = MKCoordinateSpanMake(0.01, 0.01);
    [_mapa setRegion:mapRegion animated:YES];

    [_mapa selectAnnotation:_puntoTiendaUNAM animated:NO];
}

- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
    // Volvemos a mostrar el callout, por default es 'animated = YES'
    [_mapa performSelector:@selector(selectAnnotation:animated:) withObject:_puntoTiendaUNAM afterDelay:0.5f];
}


- (IBAction)seleccionarTipoMapa:(id)sender
{
    UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;
    NSInteger indiceSeleccionado = [segmentedControl selectedSegmentIndex];

    switch (indiceSeleccionado) {

        case 0:     // Mapa tipo Normal
            [_mapa setMapType:MKMapTypeStandard];
            break;

        case 1:     // Mapa tipo Hibrido
            [_mapa setMapType:MKMapTypeHybrid];
            break;

        case 2:     // Mapa tipo Satelite
            [_mapa setMapType:MKMapTypeSatellite];
            break;

        default:
            break;
    }
}

@end

Edit with Anna suggestions The code is 编辑与安娜的建议代码是

This line is causing the EXC_BAD_ACCESS: 此行导致EXC_BAD_ACCESS:

[mapView selectAnnotation:annotation animated:YES];

You should not try to select an annotation from the viewForAnnotation delegate method itself. 您不应该尝试从viewForAnnotation委托方法本身中选择一个注释。

Remove the call to selectAnnotation:animated: from the viewForAnnotation method. viewForAnnotation方法中删除对selectAnnotation:animated:viewForAnnotation


When selectAnnotation:animated: is called, the map view needs to redraw the annotation view and show its callout. selectAnnotation:animated: ,地图视图需要重绘注释视图并显示其标注。 Redrawing the view causes viewForAnnotation to be called. 重绘视图将导致viewForAnnotation被调用。 Since in that method, the code is calling selectAnnotation:animated: it causes viewForAnnotation to get called again, and so on resulting in the crash after it runs out of memory for the recursion. 因为在该方法中,代码正在调用selectAnnotation:animated:它导致viewForAnnotation再次被调用,依此类推,导致递归用完内存后崩溃。

If you want to have an annotation's callout show as soon as it's added to the map, do it in the didAddAnnotationViews delegate method instead. 如果要在将注释的标注添加到地图后立即对其进行显示,请改为在didAddAnnotationViews委托方法中进行显示。 See MKAnnotation not getting selected in iOS5 for an example of this. 有关此示例,请参见在iOS5中未选择MKAnnotation Also note that only one annotation can be selected (show its callout) at a time. 另请注意, 一次只能选择一个注释(显示其标注)。



Unrelated to the issue but instead of setting a tag on the accessory views like this: 与问题无关,但不是像这样在附件视图上设置标签:

 [[pinView rightCalloutAccessoryView] setTag:1]; // Ver Info [[pinView leftCalloutAccessoryView] setTag:2]; // Hacer Zoom 

in calloutAccessoryControlTapped , you can just directly check if control itself equals the right or left accessory view. calloutAccessoryControlTapped ,您可以直接检查control 本身是否等于右侧或左侧附件视图。 See How to connect map annotation view buttons with database to go to another view? 请参见如何将地图注释视图按钮与数据库连接以转到另一个视图? for an example. 举个例子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM