CollectionView + UIKit Динамика сбой на performBatchUpdates:

Я застрял в странной катастрофе и пытался исправить ее весь день. У меня есть пользовательский UICollectionViewLayout, который в основном добавляет силы тяжести и столкновения по отношению к ячейкам.

Реализация отлично работает! Проблема возникает, когда я пытаюсь удалить одну ячейку, используя: [self.collectionView performBatchUpdates:].

Это дает мне следующую ошибку:

2013-12-12 21:15:35.269 APPNAME[97890:70b] *** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-2935.58/UICollectionViewData.m:357 2013-12-12 20:55:49.739 APPNAME[97438:70b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView recieved layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0x975d290> {length = 2, path = 0 - 4}' 

Моя модель обрабатывается правильно, и я вижу, как она удаляет элемент из него!

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

Вот код, который я использую для удаления ячейки.

 - (void)removeItemAtIndexPath:(NSIndexPath *)itemToRemove completion:(void (^)(void))completion { UICollectionViewLayoutAttributes *attributes = [self.dynamicAnimator layoutAttributesForCellAtIndexPath:itemToRemove]; [self.gravityBehaviour removeItem:attributes]; [self.itemBehaviour removeItem:attributes]; [self.collisionBehaviour removeItem:attributes]; [self.collectionView performBatchUpdates:^{ [self.fetchedBeacons removeObjectAtIndex:itemToRemove.row]; [self.collectionView deleteItemsAtIndexPaths:@[itemToRemove]]; } completion:nil]; } 

Делегаты CollectionView, которые обрабатывают атрибуты ячейки, являются базовыми ниже.

 - (CGSize)collectionViewContentSize { return self.collectionView.bounds.size; } - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [self.dynamicAnimator itemsInRect:rect]; } - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; } 

Вещи, которые я уже пробовал без успеха: – Нарушение макета – Перезагрузка данных – Удаление поведения из UIDynamicAnimator и добавление их снова после обновления

Какие-нибудь идеи?

Исходный код с проблемой доступен в этом репозитории. Пожалуйста, проверьте это. Репозиторий кода

Лучший. Джордж.

4 Solutions collect form web for “CollectionView + UIKit Динамика сбой на performBatchUpdates:”

После нескольких недель борьбы с этой ошибкой, некоторые полезные идеи от наших друзей @ david-h и @erwin, а также некоторые звонки и электронные письма от WWDR от Apple, я смог понять эту проблему. Просто хочу поделиться решением с сообществом.

  1. Проблема. У UIKit Dynamics есть некоторые вспомогательные методы для работы с Collection Views, и эти методы фактически не делают некоторые внутренние вещи, которые, как я думаю, должны делать автоматически, например, автоматически обновлять динамически анимированные ячейки, когда выполняется какое-либо действие с использованием функции performBatchUpdates:. Таким образом, вы должны сделать это вручную в соответствии с WWDR, ​​поэтому мы перебираем обновляемые обновления, обновляя их NSIndexPaths, чтобы динамический аниматор мог дать нам правильные обновления в ячейках.

  2. Баг. Даже делая это обновление IndexPath при вставке / удалении ячеек, у меня было много случайных сбоев и странного поведения с анимацией. Итак, я следил за советом, данным @erwin, который заключается в повторной инициализации UIDynamicAnimator после выполнения executeBatchUpdates: и это устраняет все проблемы с такой ситуацией.

Итак, код.

 - (void)removeItemAtIndexPath:(NSIndexPath *)itemToRemove completion:(void (^)(void))completion { UICollectionViewLayoutAttributes *attributes = [self.dynamicAnimator layoutAttributesForCellAtIndexPath:itemToRemove]; if (attributes) { [self.collisionBehaviour removeItem:attributes]; [self.gravityBehaviour removeItem:attributes]; [self.itemBehaviour removeItem:attributes]; // Fix the problem explained on 1. // Update all the indexPaths of the remaining cells NSArray *remainingAttributes = self.collisionBehaviour.items; for (UICollectionViewLayoutAttributes *attributes in remainingAttributes) { if (attributes.indexPath.row > itemToRemove.row) attributes.indexPath = [NSIndexPath indexPathForRow:(attributes.indexPath.row - 1) inSection:attributes.indexPath.section]; } [self.collectionView performBatchUpdates:^{ completion(); [self.collectionView deleteItemsAtIndexPaths:@[itemToRemove]]; } completion:nil]; // Fix the bug explained on 2. // Re-instantiate the Dynamic Animator self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; [self.dynamicAnimator addBehavior:self.collisionBehaviour]; [self.dynamicAnimator addBehavior:self.gravityBehaviour]; [self.dynamicAnimator addBehavior:self.itemBehaviour]; } } 

Я открыл Radar, объяснив вопрос, ожидая, что Apple исправит это в будущем обновлении. Если кто-то хочет его дублировать, он доступен на OpenRadar .

Всем спасибо.

Я столкнулся с подобной ситуацией.

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

Для меня удаление среднего UICollectionViewCell, похоже, работает (без сбоев), но приложение затем сработает, если я попытаюсь удалить последнюю ячейку.

Тщательный осмотр поведения аниматора (используя журналы отладки) показывает, что пути указателя на оставшиеся элементы действительно удалены одним удаленным элементом. Ручное их сброс само по себе не устраняет проблему.

Проблема заключается в несоответствии между количеством ячеек в представлении коллекции и количеством элементов, возвращаемых динамическим аниматором -itemsInRect: (все мои ячейки всегда видны).

Я могу предотвратить сбой, удалив все поведения до того, как я удалю ячейку. Но, конечно, это приводит к нежелательному движению моих клеток, когда вложения уходят.

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

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

Кажется, что он работает хорошо и, вероятно, может быть дополнительно оптимизирован.

 - (void)detachItemAtIndexPath:(NSIndexPath *)indexPath completion:(void (^)(void))completion { for (UIAttachmentBehavior *behavior in dynamicAnimator.behaviors) { UICollectionViewLayoutAttributes *thisItem = [[behavior items] firstObject]; if (thisItem.indexPath.row == indexPath.row) { [dynamicAnimator removeBehavior:behavior]; } if (thisItem.indexPath.row > indexPath.row) { thisItem.indexPath = [NSIndexPath indexPathForRow:thisItem.indexPath.row-1 inSection:0]; } } NSArray *tmp = [NSArray arrayWithArray:dynamicAnimator.behaviors]; self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; for (UIAttachmentBehavior *behavior in tmp) { [dynamicAnimator addBehavior:behavior]; } // custom algorithm to place cells for (UIAttachmentBehavior *behavior in dynamicAnimator.behaviors) { [self setAnchorPoint:behavior]; } [self.collectionView performBatchUpdates:^{ [self.collectionView deleteItemsAtIndexPaths:@[indexPath]]; } completion:^(BOOL finished) { completion(); }]; 

}

Во-первых, удивительный проект! Мне нравится, как ящики подпрыгивают. Кажется, что всегда есть один недостающий – ряд 0. В любом случае, любой, кто читает это, кто заинтересован в макете, должен его увидеть! Любите анимацию.

В … Layout.m:

Изменен этот метод, чтобы просто перезагрузить:

 - (void)removeItemAtIndexPath:(NSIndexPath *)itemToRemove completion:(void (^)(void))completion { //assert([NSThread isMainThread]); UICollectionViewLayoutAttributes *attributes = [self.dynamicAnimator layoutAttributesForCellAtIndexPath:itemToRemove]; [self.collisionBehaviour removeItem:attributes]; [self.gravityBehaviour removeItem:attributes]; [self.itemBehaviour removeItem:attributes]; completion(); [self.collectionView reloadData]; } 

Я добавил эти сообщения журнала:

 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSLog(@"ASKED FOR LAYOUT ELEMENTS IN RECT"); NSArray *foo = [self.dynamicAnimator itemsInRect:rect]; NSLog(@"...LAYOUT ELEMENTS %@", foo); return foo; } 

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

 CollectionViewDynamics[95862:70b] ASKED FOR LAYOUT ELEMENTS IN RECT CollectionViewDynamics[95862:70b] ...LAYOUT ELEMENTS ( "<UICollectionViewLayoutAttributes: 0x109405530> index path: (<NSIndexPath: 0xc000000000008016> {length = 2, path = 0 - 1}); frame = (105.41 -102.09; 100.18 100.18); transform = [0.99999838000043739, -0.0017999990280001574, 0.0017999990280001574, 0.99999838000043739, 0, 0]; ", "<UICollectionViewLayoutAttributes: 0x10939c2b0> index path: (<NSIndexPath: 0xc000000000018016> {length = 2, path = 0 - 3}); frame = (1 -100.5; 100 100); ", "<UICollectionViewLayoutAttributes: 0x10912b200> index path: (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}); frame = (3 468; 100 100); " ) CollectionViewDynamics[95862:70b] *** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-2935.80.1/UICollectionViewData.m:357 

Фиксация, которая должна вас заставить (надеюсь). NSLog был моим лучшим другом годами! YMMV

решил аналогичную проблему одной строкой

 self.<#custom_layout_class_name#>.dynamicAnimator = nil; 

Должны бросать его каждый раз при обновлении источника данных

  • Ограничение вертикального перемещения UIAttachmentBehavior внутри UICollectionView
  • Динамика UIKit: распознавание закругленных фигур и границ
  • Динамика UIKit Dynamics «SolveVelocityConstraints»
  • Можно ли приостановить UIDynamicAnimator без удаления и добавления UIDynamicBehaviours?
  • Экран выбора жанра Apple Music
  • UIDynamicAnimator Встряска с пружинным эффектом
  • Как копировать сообщения, отскакивающие пузырьки в iOS 7
  • UIKit Dynamics изменяет структуру представления с коллизиями
  • UICollectionViewFlowLayout привязывает ячейку к месту с помощью UIKitDynamics
  • Анимировать автоматический макет с использованием UIKitDynamics
  • Внедрение UIKitDynamics для перетаскивания изображения с экрана
  • Interesting Posts

    Как мы можем сохранить размер шрифта текстового поля относительно размера экрана?

    Отключите масштабирование интерфейса UIWebView, но сохраните другое взаимодействие с пользователем.

    iOS Swift: AWS SDK – загрузка файла с S3 – получение содержимого без сохранения файла

    QLPreviewController с NSData?

    Как я могу получить уведомление о соединении Bluetooth, когда приложение iOS основано на Xamarin?

    Почему мое приложение падает, когда я добавляю строку вставки в мой вид таблицы?

    Лучший способ передачи данных между viewcontrollers (данные кэша) в MonoTouch

    Доступ к контейнеру Cloudkit, отличному от стандартного, с Swift

    почему CocoasPod увеличивает размер IPA? как уменьшить размер?

    Пользовательский заголовок UITableView исчезает после предупреждения о памяти

    Можно ли обнаружить музыку не-ipod?

    поддельный вызов функции applicationDidReceiveMemoryWarning срабатывает, даже если у меня осталось около 80 МБ ОЗУ

    MKMapView autorelease не вызывает dealloc после того, как UIViewController выскочил

    Использование изображений .jpg в каталогах активов, разбитых на Xcode 7

    Почему автозапуск очень несовместим иногда

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.