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; 

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

  • Внедрение UIKitDynamics для перетаскивания изображения с экрана
  • Динамика UIKit на UITableView
  • Можно ли приостановить UIDynamicAnimator без удаления и добавления UIDynamicBehaviours?
  • Ограничение вертикального перемещения UIAttachmentBehavior внутри UICollectionView
  • Динамика UIKit: приложение внутри UITableViewCell
  • Встряхните UIView ... но используя UIKit Dynamics
  • Динамика UIKit: распознавание закругленных фигур и границ
  • Как вы достигаете той же анимации, что и приложение iOS 7 Reminders с UIKit Dynamics?
  • UICollectionView для самостоятельной калибровки на iOS 8 будет сбой с UIDynamic flowLayout и повторением вызова _updateVisibleCellsNow
  • UIDynamicAnimator Встряска с пружинным эффектом
  • Как я могу ускорить работу UISnapBehavior?
  • Interesting Posts

    Имя CBPeripheral не обновляется

    iOS не получает уведомления о Push-системе Firebase, отправленные через API

    Разница между @property и переменной в объявлении интерфейса

    AVPlayer UITapGestureRecognizer не работает

    iOS – Как использовать наследование в пользовательской ячейке?

    Дифференцируйте касание пальца и руки / подставки для рук

    Apple push notifications больше не прибывает

    Как подключиться к просмотрам приложений в App Store в iOS 11

    Подкласс SKNodes, созданный с помощью файла сценария SpriteKit .sks

    Linphone для iOS

    Как создать AVAsset из изображения

    Не работает рабочий файл UINavigationController interactivePopGestureRecognizer

    AFNetworking. проверять ход выполнения для всех операций

    Значение AppleLanguages ​​переопределяет значение языка, установленного в настройках IOS, предпочтительный язык

    Маленькие конечные растровые изображения и «Невозможно создать GMSGLImageTile из-за плохих графических данных»

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