Отладка сбой в CoreGraphics/MapKit

Я получаю прерывистый сбой, когда мое приложение работает на iPhone. Все аварии идентичны и в некоторой степени связаны с MKMapView Overlays (MKCircleViews).

Из типичного отчета о сбое iPhone 4s:

Заголовок отчета:

Hardware Model:      iPhone4,1
Process:         EL-GPS-01 [1021]
Path: /var/mobile/Applications/61288E15-74B5-45B9-99A9-E0B58C767816/EL-GPS-01.app/EL-GPS-01
Identifier:      EL-GPS-01
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]

Date/Time:       2011-11-22 15:59:41.065 +0000
OS Version:      iPhone OS 5.0.1 (9A405)
Report Version:  104

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000
Crashed Thread:  6

И разбитая нить:

Thread 6 name: Dispatch queue: com.apple.root.default-priority
Thread 6 Crashed:
0 ??? 0000000000 0 + 0
1 CoreGraphics 0x319a87c2 0x31967000 + 268226
2 CoreGraphics 0x3199a9e6 0x31967000 + 211430
3 MapKit 0x37ec3564 0x37e6f000 + 345444
4 MapKit 0x37ec3652 0x37e6f000 + 345682
5 MapKit 0x37ecc0a4 0x37e6f000 + 381092
6 QuartzCore 0x3341be18 0x33410000 + 48664
7 QuartzCore 0x334d77e0 0x33410000 + 817120
8 QuartzCore 0x3346af24 0x33410000 + 372516
9 libdispatch.dylib 0x3797e892 0x3797b000 + 14482
10 libsystem_c.dylib 0x360e31ca 0x360d9000 + 41418
11 libsystem_c.dylib 0x360e30a0 0x360d9000 + 41120

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

warning: check_safe_call: could not restore current frame
warning: Unable to restore previously selected frame.

Отладчик ничего мне не дает, и навигатор проблем показывает разбитый поток, в котором ничего нет.

Существует очень простой проект, освещающий проблему:

https://github.com/1ndivisible/MKOverlayBug

[email protected]:1ndivisible/MKOverlayBug.git

Я не уверен, как подойти к этому. Есть ли здесь информация, которую я могу использовать? Кажется, что авария происходит глубоко в рамках.

Ответ 1

Его известная ошибка. Apple это подтвердила. В настоящее время нет исправления. Все, что вы можете сделать, это объединить графику с меньшим количеством аннотаций. Я нашел <= 3 аннотаций в безопасности.

Ответ 2

Я думаю, что у вас заканчивается память или вы сталкиваетесь с ошибкой в ​​MapKit. Но в этом обозрение кажется, что вы неправильно используете наложения и MK-представления и перегружаете MKMapView, отслеживая так много потенциальных оверлеев. Дело в точке. При следующем методе вы добавляете 50 оверлей к текущему местоположению:

-(void)addOverlays
{
    CLLocation *currentLocation = self.mapView.userLocation.location;

    for(int i = 0; i < 50; i++)
    {
       MKCircle *circle = [MKCircle circleWithCenterCoordinate:currentLocation.coordinate radius:50];
       [self.mapView addOverlay:circle];
    }
}

со временем это может добавить к большому количеству наложений, которые MKMapView должен отслеживать и MKViews, которые он потенциально должен отображать сразу. С вашим примером кода и симулятором местоположения симулятора iPhone простой маршрут езды на велосипеде, накопленный за 1800 MKCircle и MKCircleViews в MKMapView.

Вот несколько вещей, которые нужно иметь в виду:

  • Не добавляйте столько наложений на место. 1 достаточно. 50 является излишним.
  • Один MKCircle должен быть достаточным для каждого местоположения. Не уверен, почему вы выбираете отслеживать и рисовать столько кругов на каждом место.
  • Постарайтесь быть более эффективными при переносе наложений на MapView. Только дайте ему наложения, которые ему нужны для той части карты, на которой она находится показ. Посмотрите видео WWDC2011 "Сессия 111 - Визуализация Информация географически с MapKit ", которая показывает, как оптимизировать это или код примера HazardMap.

Вы можете сделать что-то в этом направлении:

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
  {
    // Add it to an NSArray that you use to keep track of ALL the overlays
    [self.allOverlays addObject: MKCircle *circle = [MKCircle circleWithCenterCoordinate:currentLocation.coordinate radius:50]];

     // Now add it to the mapView if it is in the current region

     // code to check to see if currentLocation is within the current map region

     if (overlayIsInMapRegion){
         [mapView addOverlay: circle];
     } 
}

Затем, всякий раз, когда изменяется область, вычисляйте оверлеи, которые необходимы, когда MapView вызывает метод делегата:

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated

получить область из mapView и создать массив наложений, которые расположены в этом регионе. Что-то вроде:

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
    // Create a method that takes the region and calculates which overlays it contains
    NSArray *newOverlays=[self overlaysForRegion: mapView.region fromAllOverlays: self.allOverlays];
    if ([newOverlays count]>0){
         [mapView removeOverlays];
         [mapView addOverlays: newOverlays];
    }

}

Надеюсь, это поможет. Удачи!

Тим

Ответ 3

KERN_INVALID_ADDRESS на 0x00000000 Сбой Тема: 6

Это говорит вам, что что-то пыталось снять ссылку с нулевого указателя. Вероятно, вы выпустили аннотацию или некоторые данные, относящиеся к аннотации, когда вам этого не нужно. Запустите приложение под отладчиком с включенными зомби и посмотрите, что вы получаете.

Кроме того, запустите статический анализатор над вашим проектом и исправьте все обнаруженные проблемы.

Ответ 4

Я не работаю с mapkit до сих пор. Но самое лучшее, что я нашел, это техника отладки. Эта ссылка определенно поможет вам в отладке вашего сбоя. Это помогает практически во всех моих проектах при работе без ARC. Вам нужно очень тщательно анализировать выходные данные отладки.

http://www.cocoadev.com/index.pl?DebuggingAutorelease

Надеюсь, это поможет вам отладить сбой...

nJoy CoDing...:)

Ответ 5

В этом случае он может пытаться выполнить код по адресу 0 (вместо того, чтобы получать от него данные). Если вы снова получите его в отладчике, проверьте значение в регистре ПК. Если значение равно нулю, вы выполняете нулевое значение, а не извлекаете данные.

Если это так, возможно, ваш стек поврежден во время выполнения. Некоторое переполнение буфера локальной переменной может поместить нуль в обратный адрес кадра стека.