Связанное с KVO исключение EXC_BAD_ACCESS для свойства позиции CALayer - PullRequest
0 голосов
/ 02 февраля 2011

У меня возникли проблемы с отладкой того, что похоже на исключение EXC_BAD_ACCESS, связанное с KVO, в 10.6.6.

Я установил наблюдателя для свойства position подкласса CALayer. Этот конкретный слой является слоем контента для пользовательского слоя прокрутки CALayer. По сути, когда пользователь перетаскивает слой контента, мне бы хотелось, чтобы при изменении положения для слоя появлялись уведомления KVO, чтобы я мог обновить некоторые пользовательские скроллеры CALayer.

Выше все отлично работает.

Теперь я добавил эффект резиновой ленты в виде iOS, так что когда пользователь прокручивает границы области содержимого, возникает некоторое сопротивление, и когда пользователь отпускает мышь, слой содержимого привязывается к предельному положению в измерениях x и y. Вертикальная оснастка работает как шарм. Однако по какой-то причудливой причине любая горизонтальная привязка приводит к возникновению вышеуказанного исключения.

Что я не понимаю, так это то, почему точно один и тот же путь кода (вертикальная обратная или горизонтальная обратная) может привести к тому, что эти две ситуации будут вести себя по-разному? Вот трассировка стека:

0 0x7fff810bbc2b в CALayerTransactionFlagsLocation_
1 0x7fff810bbe00 в CALayerMark
2 0x7fff810bd394 в свойствоDidChange
3 0x7fff810bcbff в endChange
4 0x7fff810bc9f3 in - [CALayer setPosition:]
5 0x100038578 в - [MRContextualScrollLayer scrollDidEnd] в MRContextualScrollLayer.m: 280
...

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

Я попытался включить NSZombieEnabled, задав переменную окружения в аргументах исполняемого файла в XCode, но это не имеет никакого эффекта, то есть дополнительная информация не регистрируется. Это заставляет меня поверить, что проблема не в переполнении памяти, когда к объекту обращаются, чего не должно быть.

Последняя строка в методе scrollDidEnd, которая приводит к публикации уведомления KVO (что затем приводит к сбою), просто:

    _contentLayer.position = CGPointMake(_contentLayer.position.x + snapBackOffset.x,
                                         _contentLayer.position.y + snapBackOffset.y);  

У кого-нибудь есть идеи или полезные советы?

Ответы [ 2 ]

0 голосов
/ 23 февраля 2011

Обнаружение!

Устанавливая точку останова в методе -dealloc и проходя через нее, я вижу в Xcode, что

# 3 0x7fff810bf352 в CA :: Transaction :: commit

получает сообщения непосредственно перед сбоем.Это имеет смысл, поскольку я отключаю и снова включаю CA-анимацию в коде обновления скроллера, используя шаблон:

  // Disable animation temporarily.
  [CATransaction flush];
  [CATransaction begin];
  [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

  //
  // Update position of CA scrollers.
  //

  // Re-enable animation.
  [CATransaction commit];

Если я удаляю эту логику отключения анимации CATransaction, все работает нормально.

Может показаться, что явные транзакции (такие как шаблон обертки выше) не поддерживаются в контексте неявных транзакций CALayer, связанных с KVO, даже через документы говорят, что вложенные транзакции поддерживаются.Именно здесь добавлен элемент KVO, который вызывает проблему.

Из документации CATransaction:

CATransaction - это базовый механизм анимации для пакетирования нескольких операций дерева слоев в элементарных обновленияхвизуализировать дерево.Каждая модификация дерева слоев должна быть частью транзакции.Поддерживаются вложенные транзакции.

Core Animation поддерживает два типа транзакций: неявные транзакции и явные транзакции.Неявные транзакции создаются автоматически, когда дерево слоев изменяется потоком без активной транзакции, и фиксируются автоматически при следующей итерации цикла выполнения потока.Явные транзакции происходят, когда приложение отправляет классу CATransaction начальное сообщение перед изменением дерева слоев, а затем сообщение фиксации.

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

0 голосов
/ 03 февраля 2011

Правильная переменная окружения не NSEnableZombies, а NSZombieEnabled.Вот почему установка первого ничего не сделала.

Инструмент «Зомби» от инструментов более полезен.Вы можете перейти прямо от сообщения «сообщение о зомби» (которое отображается на временной шкале в виде флага) к исследованию сообщения и зомби в нижней половине окна.

...