SEGV_ACCERR вызывает [[NSNotificationCenter defaultCenter] removeObserver:self] в Dealloc

Я действительно в недоумении, как это произошло. У меня есть приложение, которое использует ARC. Большинство контроллеров моего представления регистрируются для NSNotifications. Все регистрации проходят в основном потоке.

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

В частности, он удалял себя из всех уведомлений NSNotificationCenter.

Метод Dealloc также работал в основном потоке, поэтому я не понимаю, как это может быть проблемой с потоками.

Разбитая строка -[SearchTabViewController dealloc] (SearchTabViewController.m:44)

Эта строка в коде: [[NSNotificationCenter defaultCenter] removeObserver:self];

Фактическая причина сбоя, по-видимому, objc_msgSend ссылается на освобожденный объект.

Проблема в том, что здесь отправляется только 2 сообщения: сообщение defaultCenter классу NSNotificationCenter (которое никогда не может быть недействительной ссылкой, потому что это класс) и сообщение removeObserver: центральному объекту по умолчанию (также никогда не может быть освобождено). потому что это синглтон).

Единственный другой объект, на который ссылаются, это self, который еще не может быть освобожден, потому что мы все еще находимся в методе «dealloc» для этого объекта... По сути, этого сбоя не должно было произойти.

Есть ли что-то, что мне здесь не хватает? Соответствующая часть журнала сбоев ниже:


Exception Type:  SIGSEGV
Exception Codes: SEGV_ACCERR at 0xe0000008
Crashed Thread:  0

Thread 0 Crashed:
0   libobjc.A.dylib                     0x000035b0 objc_msgSend + 16
1   Anghami Beta                        0x000c7473 -[SearchTabViewController dealloc] (SearchTabViewController.m:44)
2   CoreFoundation                      0x00003311 CFRelease + 101
3   CoreFoundation                      0x0000d95d -[__NSArrayM dealloc] + 141
4   Anghami Beta                        0x0033e73f -[EX2NavigationController .cxx_destruct] (EX2NavigationController.m:51)
5   libobjc.A.dylib                     0x00007f3d object_cxxDestructFromClass(objc_object*, objc_class*) + 57
6   libobjc.A.dylib                     0x000050d3 objc_destructInstance + 35
7   libobjc.A.dylib                     0x000053a7 object_dispose + 15
8   UIKit                               0x000cec89 -[UIViewController dealloc] + 1181
9   CoreFoundation                      0x00003311 CFRelease + 101
10  CoreFoundation                      0x0000da13 -[__NSArrayI dealloc] + 79
11  libobjc.A.dylib                     0x00005489 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 169
12  CoreFoundation                      0x00005441 _CFAutoreleasePoolPop + 17
13  CoreFoundation                      0x00095f41 __CFRunLoopRun + 1297
14  CoreFoundation                      0x00008ebd CFRunLoopRunSpecific + 357
15  CoreFoundation                      0x00008d49 CFRunLoopRunInMode + 105
16  GraphicsServices                    0x000052eb GSEventRunModal + 75
17  UIKit                               0x00057301 UIApplicationMain + 1121
18  Anghami Beta                        0x0000334d main (main.m:17)

person Ben Baron    schedule 15.10.2012    source источник


Ответы (1)


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

Теперь в Dealloc я обнуляю делегата загрузчика и отменяю загрузку, если она активна, и вуаля больше никаких сбоев.


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

Поэтому лучше всего перейти к Edit Scheme и включить там объекты-зомби, затем собрать и запустить на устройстве и дождаться его сбоя. Таким образом вы не получите полную историю сохранения/релиза, но, как и в этом случае, она может дать достаточно информации, чтобы отследить неуловимую проблему.

person Ben Baron    schedule 16.10.2012