Непрерывное падение в MKMapView annotationContainer: viewForAnnotation - PullRequest
3 голосов
/ 16 ноября 2011

Я просмотрел другие отчеты по этому вопросу, и, похоже, ни один из них не подходит. Наше приложение наносит вред частым (но не надежно воспроизводимым) сбоям, подобным этому:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x333a6c98 objc_msgSend + 16
1   MapKit                          0x30be52fc -[MKMapView annotationContainer:viewForAnnotation:] + 36
2   MapKit                          0x30be4f8e -[MKAnnotationContainerView _addViewForAnnotation:] + 270
3   MapKit                          0x30c0f164 -[MKAnnotationContainerView addViewForManagedAnnotation:notifyDelegate:] + 12
4   MapKit                          0x30c0b874 -[MKMapView(UserPositioningInternal) _runPositioningChange] + 1036
5   MapKit                          0x30c09a86 -[MKMapView(UserPositioningInternal) _startPositioningChange:] + 22
6   MapKit                          0x30c0d04a -[MKMapView(UserPositioningInternal) locationManagerUpdatedLocation:] + 578
7   CoreFoundation                  0x360bcefc -[NSObject(NSObject) performSelector:withObject:] + 16
8   CoreFoundation                  0x360fa2f2 -[NSArray makeObjectsPerformSelector:withObject:] + 394
9   MapKit                          0x30bfc802 -[MKLocationManager _reportLocationStatus:] + 34
10  MapKit                          0x30bfdd6c -[MKLocationManager _reportLocationSuccess] + 36
11  MapKit                          0x30bfd9c6 -[MKLocationManager locationManager:didUpdateToLocation:fromLocation:] + 674

Сообщения об этом часто появляются в Интернете, но многие, похоже, остаются нерешенными. Я не делаю ничего сумасшедшего, просто показываю положение пользователя и один маркер на карте. Я следовал за примерами, которые мог найти, и посмотрел код для глупостей, но не смог найти ни одного.

Вот как мой делегат MapView обрабатывает viewForAnnotation:

- (MKAnnotationView*)mapView:(MKMapView*)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    // If it's the user location, just return nil.
    if([annotation isKindOfClass:[MKUserLocation class]])
    {
        return nil;     // Use default system user-location view.
    }
    else
    {
        // Try to dequeue an existing pin view first.
        MKPinAnnotationView* pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"stashMarkerID"];
        if(!pinView)
        {
            // If an existing pin view was not available, create one.
            pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation
                                                       reuseIdentifier:@"stashMarkerID"] autorelease];
            pinView.pinColor = MKPinAnnotationColorPurple;
            pinView.animatesDrop = YES;
            pinView.canShowCallout = NO;
        }
        else
        {
            pinView.annotation = annotation;
        }

        return pinView;
    }
}

Похоже, что сбой связан с изменением местоположения пользователя, но как только маркер местоположения пользователя добавлен, я не связываюсь с ним. Когда мне нужно обновить еще один маркер карты, я пропускаю пользовательский маркер при удалении другого:

// Add the marker to the map.
// Remove old one(s) first.
int i = 0;
while(i < [mapView.annotations count])
{
    if ([[mapView.annotations objectAtIndex:i] isKindOfClass:[StashMarker class]])
    {
        [mapView removeAnnotation:[mapView.annotations objectAtIndex:i]];
    }
    else
    {
        i++;
    }
}

Делегат является контроллером для всего экрана, поэтому он не освобождается; сбой происходит, когда экран вверх. Не то, чтобы это имело значение, но отображение карты выглядит так:

enter image description here

Любые догадки или идеи будут высоко оценены! Это на iOS 5.0.1.

ОБНОВЛЕНИЕ: Мы обнаружили, что этот сбой происходит, когда MKMapView вообще не должно существовать. Представление, содержащее это, уже давно появилось. Интересно, если мы столкнулись с проблемой, о которой сообщалось здесь: MKMapView аварийно завершает работу приложения, когда контроллер представления отключен

ОБНОВЛЕНИЕ 2: Вот еще один отчет по существу того же самого вопроса: Почему у меня происходит сбой после освобождения MKMapView, если я больше его не использую?

Это кажется необычно грязным для Какао, когда необходимо установить для делегата MKMapView значение nil после того, как мы ожидаем, что MapView будет освобожден. В таком случае, почему мы не должны делать это для всех элементов управления, которые принимают делегата?

Ответы [ 3 ]

10 голосов
/ 21 ноября 2011

ОК, это реальный ответ.Это из документа Apple, но он отсутствует в MKMapView.Его можно найти только в документации к его протоколу делегата:

"Перед выпуском объекта MKMapView, для которого вы установили делегат, не забудьте установить свойство делегата этого объекта равным nil. В одном месте вы можете сделать это вМетод dealloc, в котором вы избавляетесь от вида карты. "

ПРИМЕЧАНИЕ. Это также относится к UIWebView.

Я установил указатель делегата MapView равным nil в методе dealloc делегата, и наши сбои кажутсябыли устранены.

2 голосов
/ 26 сентября 2012

У меня была похожая проблема, и я попробовал ваше решение, чтобы установить mapView.delegate=nil, но оно работает только в первый раз, когда я перерисовываю вид карты.после второго тайма вылетает.В моем случае ошибка происходит в этой строке.[CLPlacemark dealloc]

А мой 'StashMarker' является производным от MKPlacemark.Поэтому я просто изменяю свой конструктор 'StashMarker' С этого

self = [super init];

На этот

self = [super initWithCoordinate:your_coord addressDictionary:[NSDictionary dictionary]];

CLPlacemark, который является родителем MKPlacemark, а вашему классу аннотаций требуется addressDictionary дляотпущена.

0 голосов
/ 17 ноября 2011

(Отказ от ответственности: я не знаю, является ли это причиной вашей проблемы.)

В комментариях я сказал:

Я бы удалиланнотации путем добавления единиц для удаления в другой массив и последующего вызова removeAnnotations (множественное число) вместо удаления на месте и использования специального индекса для ссылки на аннотацию.

, и вы спросили:

Есть ли какая-либо конкретная причина, по которой вы бы предпочли собрать аннотации для удаления и сделать их все сразу?

На самом деле, это не часть, которая удаляет все сразуважно, но опора на индекс массива.

Я бы предпочел не предполагать, что аннотация, которую я получаю по индексу i в одной строке, все еще будет там в другое время (даже в следующей строке), даже если мой код не добавляет и не удаляет какие-либоаннотации между ними.

Представление карты (я думаю) просто предоставляет нам список аннотаций в виде массива для удобства, но внутренне оно может хранить список по-другому и может перетасовывать содержимое вокруг (но не изменять ссылки на аннотации).

Мне кажется, безопаснее не предполагать, что содержимое массива annotations останется в фиксированных позициях.

Поэтому, чтобы удалить только определенные аннотации, я бы предпочел следующее:

NSMutableArray *annotationsToRemove = [NSMutableArray array];

for (id<MKAnnotation> ann in mapView.annotations) 
{
    if ([ann isKindOfClass:[StashMarker class]])
    {
        [annotationsToRemove addObject:ann];
    }
}

[mapView removeAnnotations:annotationsToRemove];

Опять же, это может не иметь никакого отношения к сбоям, которые вы испытываете.

...