Авария UIScrollView EXC_BAD_ACCESS в SDK для iOS
У меня есть приложение iPhone SDK, которое имеет несколько представлений, которые появляются и исчезают, когда пользователь создает контент. После использования приложения на устройстве какое-то время я получаю следующий сбой:
Program received signal: "EXC_BAD_ACCESS".
(gdb) backtrace
#0 0x33369ebc in objc_msgSend ()
#1 0x320e5248 in -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded] ()
#2 0x338b4a14 in -[NSObject performSelector:withObject:] ()
#3 0x320e5098 in -[UIAnimator stopAnimation:] ()
#4 0x320e4b7c in -[UIAnimator(Static) _advance:] ()
#5 0x320e4a34 in LCDHeartbeatCallback ()
#6 0x34350e60 in HeartbeatVBLCallback ()
#7 0x332e91c0 in IOMobileFramebufferNotifyFunc ()
#8 0x316532f8 in ?? ()
#9 0x33866b50 in __CFMachPortPerform ()
#10 0x338ae52a in CFRunLoopRunSpecific ()
#11 0x338adc1e in CFRunLoopRunInMode ()
#12 0x3434e1c8 in GSEventRunModal ()
#13 0x32002c30 in -[UIApplication _run] ()
#14 0x32001230 in UIApplicationMain ()
#15 0x00002ff8 in main (argc=1, argv=0x2ffff550) at /Developer/svn/MyCompany/iPhone/MyApplication/Other Sources/main.m:14
Как вы можете видеть из трассировки, единственное упоминание моего кода есть вызов main.
Я запускал сборку и анализ из Xcode, а также настраивал ее для запуска анализатора clang в моем проекте из терминала, и оба они не могут найти никаких проблем в коде. Я использую очень недавнюю версию iOS SDK (я еще не загрузил 4.1, но тот, который я использую, тот, который был в выпуске до 4.1).
Кроме того, я запустил приложение в Инструментах с Simulator, и приложение не имеет утечек памяти.
Я собираюсь попробовать использовать переменную NSZombieEnabled
и посмотреть, найдет ли что-нибудь что-нибудь, но проблема в том, что мне нужно использовать приложение в течение 30-40 минут или около того, прежде чем он сработает, и я подозреваю, что NSZombieEnabled
может даже не помочь мне найти проблему.
Кажется, что сбои, которые я видел, - это когда модальный вид вызывает делегата в родительском представлении. Затем контроллер родительского представления выполняет некоторую обработку перед тем, как отклонить контроллер модального представления. Есть некоторые ссылки в случае сбоя для анимации и просмотра прокрутки, но я не уверен, что бы я мог сделать, чтобы у этих проблем были проблемы. У кого-нибудь есть предложения по поиску вещей?
EDIT: Я поместил флаг NSZombieEnabled
в приложение, и на устройстве оно появилось с этим сообщением в консоли:
2010-09-11 17:10:33.970 MyApplication[9321:207] ***
-[MyViewController respondsToSelector:]: message
sent to deallocated instance 0x7489480
Насколько я могу судить, я устанавливаю делегаты, используемые в приложении, в nil в deallocs всех моих классов, поэтому я зациклен на том, где искать дальше.
Я попытался использовать команду pid address malloc_history
для этого, но он сказал, что не смог найти этот процесс, я пробовал 9321, 9321: 207 и 207. Кроме того, если я попытаюсь использовать MallocStackLogging
переменная, программа не будет запущена на устройстве, я получаю кучу malloc:
, неспособную создавать сообщения каталога журнала стека в консоли и сбой программы.
О, и, кстати, я не могу использовать проверку зомби в Инструментах, так как он не работает с устройством, и я не могу получить тот же самый крах, который должен произойти в Симуляторе.
Ответы
Ответ 1
Кадр UIScrollView
на стеке # 1, вероятно, хочет сообщить его делегату об окончании анимации, но делегат ушел в этот момент. Настройка NSZombieEnabled
, вероятно, подтвердит это.
Делегаты не сохраняются, поэтому это общая ошибка в Cocoa и Cocoa Touch. Ищите делегатов в UIScrollView
или UITableView
в вашем коде и попытайтесь выяснить, какой из них может быть выпущен до его времени.
Ответ 2
Я сам справился с этой проблемой.
У меня возникла проблема:
- Делитель scrollview был подключен к UIViewController
- Скроллвью начал анимацию
- Делегат ушел, и dealloc был вызван.
Проблема заключалась в том, что сообщения делегатов scrollview запускались на объект с невыделенным номером, и журналы сбоев были немного запутанными, поскольку они указывали на бессмысленные ссылки на объекты.
Исправление заключалось в том, чтобы установить делегат scrollview в nil как первую строку метода dealloc моего контроллера.
Надеюсь, это поможет кому-то еще!
Ответ 3
Для полноты я добавляю эту трассировку стека (iOS 6) для тех, кто может столкнуться с одной и той же проблемой, но с немного другой реализацией и точными шагами по воспроизведению проблемы.
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x71f05631
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x3919b5d0 objc_msgSend + 1
1 UIKit 0x33421830 -[UIScrollView(UIScrollViewInternal) _delegateScrollViewAnimationEnded] + 48
2 UIKit 0x334217ba -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded:finished:] + 130
3 UIKit 0x334216a4 -[UIAnimator stopAnimation:] + 460
Это происходит на iOS 6 и начинается, когда я реализовал
Метод UIScrollViewDelegate:
" -(void)scrollViewDidEndDecelerating:(UITableView *)tableView"
and made a call to:
"[tableView scrollToRowAtIndexPath: indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];".
Проблема возникла при запуске анимации, и я нажал кнопку "Назад" , и мой контроллер просмотра был удален до завершения анимации.
При воспроизведении вы должны обязательно нажать кнопку "Назад" после запуска анимации, но до ее завершения. Мне потребовалось несколько попыток. Я попытался воссоздать проблему, программно вытащив контроллер просмотра, но не смог воспроизвести его. Мне пришлось использовать кнопку "Назад" . Я просто вызывал [выпуск myTableView] в dealloc. Решение было таким, как описано здесь, чтобы установить оба этих свойства в nil:
self.myTableView.delegate = nil;
self.myTableView = nil;
Ответ 4
Во-первых, делегаты должны иметь слабый/назначать тип. Но событие в этом случае очень распространено
тонкое препятствие, вызванное анимацией прокрутки. Если вы используете изменения смещения анимированного содержимого для
ваши ScrollViews вам необходимо установить его делегат на нуль по методу dealloc.
В противном случае вы получите следующее
[YourViewController respondsToSelector:]: message sent to deallocated instance
Очень распространенный пример:
1. _tableView is ivar of YourViewController
2. _tableView.delegate = self;
3. - (void)scrollViewDidScroll:(UIScrollView *)scrollView is implemented at YourViewController
4. at some point you call [_tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom animated:YES];
or [_tableView setContentOffset:CGPoint animated:YES]
and try to close YourViewController
_tableView сохраняется в CoreAnimation, но YourViewController освобождается!
Ответ 5
Я предполагаю, что делегат scrollview будет установлен на объект, который был освобожден. Попробуйте настроить все делегаты дочерних объектов на ноль в методах dealloc.
Ответ 6
Это может произойти, если вы вставили контроллер обновления в представление таблицы в качестве подсмотра (мой намек, никогда не делайте этого)...
Ответ 7
Все вышеизложенное не исправило мою проблему, поэтому я снова выкопал свой код.
Я узнал, что авария появляется, когда я выполняю анимацию клавиатуры и UICollectionView (да, это чат) и увольняют текущий контроллер.
Сбой приложения, потому что я пытаюсь сделать прокрутку в блоке завершения анимации:)
Просто порежьте его, и теперь все хорошо работает!
Счастливое кодирование и отладка:)
Ответ 8
После того, как вы столкнулись с той же проблемой, я установил:
self.collectionView.delegate = nil;
в - (void)viewDidLoad
(перед тем, как фактически установить ViewController в качестве делегата коллекцииView)
и -(void)viewWillDisappear:(BOOL)animated
Теперь все работает отлично.
Спасибо за помощь.
Ответ 9
Я видел такое поведение, когда вызов scrollToRowAtIndexPath с отсутствующим индексом indexPath