UIScrollView аварийно завершает работу, если setContentOffset вызывается с анимацией

Мое приложение создает экземпляры пользовательского подкласса UIView и добавляет эти экземпляры, расположенные горизонтально рядом друг с другом. Когда создается новый экземпляр моего класса UIView, я могу добавить его в UIScrollView и сбросить размер содержимого. Затем я звоню [UIScrollView setContentOffset:(some point) animated:NO]. Это прекрасно работает. Проблема в том, что когда я вызываю вышеупомянутый метод с анимацией, то есть [UIScrollView setContentOffset:(some point) animated:YES] , приложение вылетает. Стек вызовов выглядит так:

> #0    0x3145b870 in ___forwarding___ ()
> #1    0x313b6650 in _CF_forwarding_prep_0 ()
> #2    0x317d84a2 in -[UIAnimator stopAnimation:] ()
> #3    0x317d84a2 in -[UIAnimator stopAnimation:] ()
> #4    0x317d7f0e in -[UIAnimator(Static) _advance:withTimestamp:] ()
> #5    0x317d7e00 in -[UIAnimator(Static) _LCDHeartbeatCallback:] ()
> #6    0x3531d86e in CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) ()
> #7    0x3531d7c4 in CA::Display::IOMFBDisplayLink::callback(__IOMobileFramebuffer*,
> unsigned long long, unsigned long long, unsigned long long, void*) ()
> #8    0x33a56000 in IOMobileFramebufferVsyncNotifyFunc ()
> #9    0x36e3c60c in IODispatchCalloutFromCFMessage ()
> #10   0x31422f12 in __CFMachPortPerform ()
> #11   0x3142d522 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
> #12   0x3142d4c4 in __CFRunLoopDoSource1 ()
> #13   0x3142c312 in __CFRunLoopRun ()
> #14   0x313af4a4 in CFRunLoopRunSpecific ()
> #15   0x313af36c in CFRunLoopRunInMode ()
> #16   0x32888438 in GSEventRunModal ()
> #17   0x316b4cd4 in UIApplicationMain ()

Когда я включаю Zombies, вывод приложения производит:

*** -[__NSArrayM removeObject:]: message sent to deallocated instance 0x113dbb10

Дополнительная информация: делегат UIScrollView никогда не устанавливается. Я использую АРК.


person Jude Pereira    schedule 13.08.2012    source источник


Ответы (2)


Я нашел свою проблему. Я вызывал метод setContentOffset из фонового потока.

BackgroundThread --> My random processing method --> Setup new UIView and add it to UIScrollView --> Call setContentOffset with animations

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

Очевидно, iOS не любит анимации, вызываемые из фонового потока.

person Jude Pereira    schedule 14.08.2012
comment
Если есть одно правило для iOS и OSX, оно никогда не манипулирует пользовательским интерфейсом в любом потоке, кроме основного потока. Правило №1. Дело не в том, что ему это не нравится, а в том, что это запрещено, и Apple документирует это более чем в одном месте. - person David H; 14.08.2012
comment
Да, я забыл о том, что я вызывал этот метод из фонового потока. Просто подумал, что опубликую свой ответ на случай, если кто-то окажется в таком же неприятном положении. - person Jude Pereira; 14.08.2012
comment
Не забудьте выбрать его в качестве ответа, когда SO позволит вам! Чтобы люди знали, что на вопрос дан ответ. - person David H; 14.08.2012

Одно из представлений в scrollView освобождается. Вероятно, вы «перепрыгиваете» через него, когда отключаете анимацию — когда она включена, система пытается получить серию «моментальных снимков» изменений, а когда она пытается получить доступ к одному просмотру, вы падаете. Таким образом, вы можете включить Zombies и узнать, какой тип объекта получает сообщение, а в отладчике вы, вероятно, сможете "по" этот объект.

Другой способ сделать это — написать нашу собственную тестовую анимацию, перемещать contentOffset, скажем, на 20 пикселей за раз в цикле без анимации, и смотреть, когда произойдет сбой (это обязательно произойдет)!

person David H    schedule 13.08.2012
comment
Я попробовал ручной цикл, и это, похоже, не вызвало никаких проблем, хотя экран как бы просто перескочил на смещение без какой-либо анимации. Мой цикл был эквивалентен вызову setContentOffset без анимации. - person Jude Pereira; 14.08.2012