Сбой UIScrollView EXC_BAD_ACCESS в iOS SDK - PullRequest
       22

Сбой UIScrollView EXC_BAD_ACCESS в iOS SDK

36 голосов
/ 10 сентября 2010

У меня есть приложение 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.

Я запустил Build and Analyze из Xcode, а также настроил его для запуска анализатора clang в моем проекте из Терминала, и оба они не могут найти никаких проблем в коде. Я использую самую последнюю версию iOS SDK (я еще не загрузил 4.1, но я использую ту, которая была выпущена прямо перед 4.1).

Кроме того, я запустил приложение в инструментах с симулятором, и приложение не имеет утечек памяти.

Я собираюсь попытаться использовать переменную NSZombieEnabled и посмотреть, найдет ли она что-нибудь, но проблема в том, что мне нужно использовать приложение в течение 30-40 минут или около того, прежде чем оно падает, и я подозреваю, что NSZombieEnabled может даже не помочь мне найти проблему.

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

РЕДАКТИРОВАТЬ: Я поместил флаг NSZombieEnabled в приложение, и на устройстве, это появляется в консоли следующее сообщение:

2010-09-11 17:10:33.970 MyApplication[9321:207] *** 
-[MyViewController respondsToSelector:]: message 
sent to deallocated instance 0x7489480

Насколько я могу судить, я устанавливаю для делегатов, используемых в приложении, nil в deallocs всех моих классов, поэтому я застрял в том, где искать дальше.

Я пытался использовать команду malloc_history pid address для этого, но он сказал, что не может найти процесс, я попытался 9321, 9321: 207 и 207. Кроме того, если я пытаюсь использовать MallocStackLogging переменная, программа не будет работать на устройстве, я получаю кучу malloc:, неспособных создать сообщения каталога стекового журнала в консоли и сбой программы.

Да, и, кстати, я не могу использовать проверку зомби в Инструментах, так как она не работает с устройством, и я не могу получить такой же сбой в симуляторе.

Ответы [ 9 ]

61 голосов
/ 05 декабря 2011

Я только что решил эту проблему сам.

У меня была проблема, где:

  • Делегат с прокруткой был подключен к UIViewController
  • Началось анимация прокрутки
  • Делегат ушел, и Деллок был вызван.

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

Исправление было в том, чтобы установить делегат scrollview равным nil в качестве первой строки моего метода dealloc контроллера представления.

Надеюсь, это поможет кому-то еще!

42 голосов
/ 10 сентября 2010

UIScrollView в кадре стека # 1, вероятно, хочет сообщить своему делегату об окончании анимации, но на этом этапе делегат пропал. Установка NSZombieEnabled, вероятно, подтвердит это.

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

16 голосов
/ 06 апреля 2013

Для полноты я добавляю эту трассировку стека (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 release] в dealloc. Решение было таким, как описано здесь, чтобы установить оба эти свойства на ноль:

self.myTableView.delegate = nil;
self.myTableView = nil;
7 голосов
/ 15 декабря 2013

Сначала делегаты должны иметь тип слабый / назначить .Но событие в этом случае является очень распространенным тонким препятствием, вызванным анимацией прокрутки.Если вы используете анимированные изменения смещения контента для 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 освобождается!

3 голосов
/ 10 сентября 2010

Я полагаю, что делегат scrollview установлен на объект, который был освобожден. Попробуйте настроить все делегаты дочерних объектов на nil в ваших методах dealloc.

2 голосов
/ 01 июля 2014

Все вышеперечисленное не решило мою проблему, поэтому я снова глубоко копал код. Я узнал, что сбой появляется, когда я выполняю анимацию клавиатуры и UICollectionView (да, это чат) и отключаю текущий контроллер.

Приложение вылетает, потому что я пытаюсь сделать прокрутку в блоке завершения анимации :)

Просто порежь и все теперь хорошо работает!

Удачного кодирования и отладки:)

2 голосов
/ 26 августа 2013

Это может произойти, если вы вставили контроллер обновления в табличное представление как подпредставление (мой совет, никогда не делайте этого) ...

1 голос
/ 15 июля 2014

Столкнувшись с той же проблемой, я установил:

self.collectionView.delegate = nil;

в - (void)viewDidLoad (до фактической установки ViewController в качестве делегата collectionView) и -(void)viewWillDisappear:(BOOL)animated

Теперь все отлично работает.

Спасибо за помощь.

0 голосов
/ 11 ноября 2015

Я видел такое поведение, когда вызывал scrollToRowAtIndexPath с не существующим indexPath

...