MKMapKit — EXC_BAD_ACCESS при переборе MKAnnotations

Я застрял на этой ошибке EXC_BAD_ACCESS уже 2 дня. У меня есть метод reloadAnnotations, который удаляет все аннотации перед добавлением новых аннотаций. Перед удалением аннотации этот метод должен проверять, содержит ли новый набор то же местоположение, чтобы он не удалялся и не добавлялся повторно. Но как только я пытаюсь отследить текущий заголовок аннотации, я получаю эту ошибку Thread 1: Program received signal: "EXC_BAD_ACCESS"

И когда я просматриваю аннотацию в отладчике, свойство заголовка говорит «Неверное резюме». Это должно быть вызвано тем, что значение не сохраняется, но я все перепробовал и не могу понять.

Почему я не могу зарегистрировать заголовок аннотации в NSLog?

И почему я не могу сравнить каждое название и координаты с другими объектами?

BrowseController.m

-(void)reloadAnnotations
{
    NSMutableArray *toRemove = [NSMutableArray arrayWithCapacity:10];
    for (id annotation in _mapView.annotations) {
        if (annotation != _mapView.userLocation) {
            //ParkAnnotation *pa = (ParkAnnotation *)annotation;
            ParkAnnotation *pa = annotation;
            NSLog(@"pa.title %@", pa.title); // Thread 1: Program received signal: "EXC_BAD_ACCESS"
            [toRemove addObject:annotation];
        }
    }
    // DON'T REMOVE IT IF IT'S ALREADY ON THE MAP!!!!!! 
    for(RKLocation *loc in locations) 
    {
        CLLocationCoordinate2D location;
        location.latitude = (double)[loc.lat doubleValue];
        location.longitude = (double)[loc.lng doubleValue];
        ParkAnnotation *parkAnnotation = [[ParkAnnotation alloc] initWithTitle:loc.name andCoordinate:location];      
        [_mapView addAnnotation:parkAnnotation];
    }
    [_mapView removeAnnotations:toRemove];
}



- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
    NSLog(@"BrowseViewController map viewForAnnotation");
    MKPinAnnotationView *pin = (MKPinAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier: @"anIdentifier"];

    if (pin == nil){
        pin = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation
                                               reuseIdentifier: @"anIdentifier"] autorelease];

        pin.pinColor = MKPinAnnotationColorRed;
        pin.animatesDrop = YES;
        pin.canShowCallout = YES;
    }
    else{
        pin.annotation = annotation;
    }
    return pin;
    }

ParkAnnotation.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface ParkAnnotation : NSObject <MKAnnotation> {

    NSString *title;
    CLLocationCoordinate2D coordinate;

}


@property (nonatomic, copy) NSString *title;  
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d;

@end

ParkAnnotation.m (отредактировано: см. комментарии Вольфганга ниже)

#import "ParkAnnotation.h"
@implementation ParkAnnotation
@synthesize title, coordinate;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d {
    self = [super init];
    if (self) { 
        title = ttl;
        coordinate = c2d;    
    } 
    return self;
}
- (void)dealloc {
    [title release];
    [super dealloc];
}
@end

person jspooner    schedule 03.06.2011    source источник
comment
Вы, вероятно, не можете сравнивать сами аннотации, поскольку они, вероятно, являются указателями на разные объекты и, следовательно, никогда не совпадают. Вместо этого вы можете попытаться сравнить фактические значения внутри указателей.   -  person Wolfgang Schreurs    schedule 03.06.2011
comment
Не могли бы вы показать свойство annotations представления карты? Как вы присваиваете значения этому свойству, используете ли вы геттеры и сеттеры или, возможно, напрямую обращаетесь к значению свойства? Свойство копирует или сохраняет свои значения?   -  person Wolfgang Schreurs    schedule 03.06.2011
comment
@Wolfgang Я собирался сравнить заголовки аннотаций и объект не MKAnnotation.   -  person jspooner    schedule 03.06.2011
comment
@Wolfgang Я не вижу _mapView.annotations в отладчике, но когда я отправляю его в NSLog, я вижу эти ‹ParkAnnotation: 0x5c7c940›, ‹MKUserLocation: 0x5a4ddb0›   -  person jspooner    schedule 03.06.2011
comment
Ах, из документации я понимаю, что это встроенное свойство, поэтому я думаю, что ошибка не будет связана с самим массивом.   -  person Wolfgang Schreurs    schedule 03.06.2011
comment
Редактировать: вероятная причина сбоя: инициализатор в ParkAnnotation.m написан не в соответствии с соглашениями ObjC. Переменная self никогда не устанавливается (self = [super init]; if (self) { /* custom initialization here ... */ } return self;). Поскольку self не задана, методы доступа, используемые в вызывающем объекте, не будут работать.   -  person Wolfgang Schreurs    schedule 03.06.2011
comment
Я тоже думал, что это исправит, но не повезло. Я также добавил NSLog в метод Dealloc ParkAnnotation, и я не вижу, чтобы он вызывался.   -  person jspooner    schedule 03.06.2011
comment
Я обновил ParkAnnotation.m в приведенном выше коде, чтобы показать ваши исправления.   -  person jspooner    schedule 03.06.2011
comment
ОК, Я НАШЕЛ ПРОБЛЕМУ! Проблема A заключалась в том, как вы сказали, устанавливая переменную self. Проблема Б заключалась в изменении title = ttl; на self.title = ttl;   -  person jspooner    schedule 03.06.2011
comment
@Wolfgang добавьте свое исправление к ответу ниже, и я проверю его для вас.   -  person jspooner    schedule 03.06.2011


Ответы (2)


Инициализатор в ParkAnnotation.m написан не в соответствии с соглашениями ObjC. Переменная self никогда не устанавливается, назначенный инициализатор класса должен следовать следующему шаблону:

- (id)init 
{
    self = [super init]; 
    if (self) 
    { 
        /* custom initialization here ... */ 
    } 
    return self;
} 

Поскольку self не установлен, методы доступа, используемые в вызывающем объекте, не будут работать; объект-контейнер (внутри ParkAnnotation.m, на который ссылается self) будет нулевым или каким-либо фиктивным значением при попытке доступа к свойству внутри объекта из другого класса.

person Wolfgang Schreurs    schedule 03.06.2011
comment
Код в вопросе jspooner изменился со вчерашнего дня. В предыдущем комментарии я упомянул об этой проблеме, и jspooner соответствующим образом изменил свой код. Он попросил меня добавить это в качестве ответа, и он проголосует за него, потому что это помогло ему решить его проблему. - person Wolfgang Schreurs; 03.06.2011
comment
Ох, хорошо. Я смотрел на этот код и задавался вопросом, почему self не будет установлен. А что касается его более раннего кода, то он будет работать, за исключением некоторых редких случаев. self устанавливается, как только выполняется выделение, а [super init] в основном влияет на один и тот же участок памяти. Мы делаем self = [super init], чтобы убедиться, что метод инициализации суперкласса не вернет что-то отличное от того, что мы выделили, как в случае с синглтоном. Таким образом, внутри оператора if должна быть проверка, не завершилось ли присваивание неудачей, поскольку мы не хотели бы вызывать методы self.* для другого объекта. - person Deepak Danduprolu; 03.06.2011

Хотя вы объявили, что title имеет свойство типа copy, оно никогда не копируется, поскольку вы не используете метод установки и не назначаете его напрямую. Вы даже выпускаете его без права собственности. Измените это так,

title = [ttl copy];
person Deepak Danduprolu    schedule 03.06.2011
comment
Лучше использовать свойство вместо переменной. Это станет self.title = ttl;. Всегда предпочтительнее использовать свойства вместо переменных, чтобы избежать проблем с памятью. Я всегда начинаю имена переменных с _, чтобы предотвратить подобные проблемы. - person Dmitry S.; 03.06.2011