TeehanLax / UICollectionView-Spring-Demo

A demonstration of UICollectionView and UIKit Dynamics
MIT License
473 stars 71 forks source link

Inserting new cells #5

Open cswelin opened 10 years ago

cswelin commented 10 years ago

I've toyed around with the example provided and added a timer to fire insertItemsAtIndexPaths every few seconds. Since I want to use a `NSFetchResultsController later on.

Not sure if i'm doing something wrong, but when the insert happens it crashes with

 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no UICollectionViewLayoutAttributes instance for -layoutAttributesForItemAtIndexPath: <NSIndexPath: 0x8e93440> {length = 2, path = 0 - 100}'
*** First throw call stack:
(
    0   CoreFoundation                      0x017395e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x014bc8b6 objc_exception_throw + 44
    2   CoreFoundation                      0x01739448 +[NSException raise:format:arguments:] + 136
    3   Foundation                          0x0109d23e -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 116
    4   UIKit                               0x0087dcd4 -[UICollectionViewData layoutAttributesForItemAtIndexPath:] + 313
    5   UIKit                               0x00853511 __51-[UICollectionView _viewAnimationsForCurrentUpdate]_block_invoke1144 + 155
    6   UIKit                               0x00850c73 -[UICollectionView _viewAnimationsForCurrentUpdate] + 2901
    7   UIKit                               0x0085447c -[UICollectionView _updateWithItems:] + 1635
    8   UIKit                               0x0084fe58 -[UICollectionView _endItemAnimations] + 14317
    9   UIKit                               0x0084c475 -[UICollectionView _updateRowsAtIndexPaths:updateAction:] + 361
    10  UIKit                               0x0084c4bc -[UICollectionView insertItemsAtIndexPaths:] + 48
    11  UIKit                               0x0de3ffc9 -[UICollectionViewAccessibility(SafeCategory) insertItemsAtIndexPaths:] + 57
    12  UICollectionView-Spring-Demo        0x00004f8d -[TLViewController addRow] + 253
    13  Foundation                          0x010f3b67 __NSFireTimer + 97
    14  CoreFoundation                      0x016f7c46 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
    15  CoreFoundation                      0x016f762d __CFRunLoopDoTimer + 1181
    16  CoreFoundation                      0x016df698 __CFRunLoopRun + 1816
    17  CoreFoundation                      0x016deb33 CFRunLoopRunSpecific + 467
    18  CoreFoundation                      0x016de94b CFRunLoopRunInMode + 123
    19  GraphicsServices                    0x036da9d7 GSEventRunModal + 192
    20  GraphicsServices                    0x036da7fe GSEventRun + 104
    21  UIKit                               0x0022f94b UIApplicationMain + 1225
    22  UICollectionView-Spring-Demo        0x0000548d main + 141
    23  libdyld.dylib                       0x01d7770d start + 1

due to [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; returning nil. How do I go about resolving this? I've noticed this same trend on other examples implementing the spring example.

ashfurrow commented 10 years ago

Hey – great question. I've had trouble doing this, too. Can you try the following?

[self.collectionView performBatchUpdates:^{
    [self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:self.count inSection:0]]];
    self.count++; // or whatever to update your number of cells
} completion:nil];

That should work – let me know either way.

cswelin commented 10 years ago

thanks for the response,

It seemed to partially work. I've started the count at 100, if I don't scroll to the bottom it will crash out. But if i'm within 2 rows of the insert it seems to work.

ashfurrow commented 10 years ago

Hmm... that's troubling. Could you zip up your source code and send it to ash@teehanlax.com ? I'd be happy to take a look.

cswelin commented 10 years ago

sure, not a problem

ashfurrow commented 10 years ago

OK I've looked into it and the solution is to add new attachment behaviours when new cells are added to the collection view. This is done with the following method, or something similar to it.

-(void)prepareForCollectionViewUpdates:(NSArray *)updateItems
{
    [super prepareForCollectionViewUpdates:updateItems];

    [updateItems enumerateObjectsUsingBlock:^(UICollectionViewUpdateItem *updateItem, NSUInteger idx, BOOL *stop) {
        if (updateItem.updateAction == UICollectionUpdateActionInsert)
        {
            UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:updateItem.indexPathAfterUpdate];

            attributes.frame = CGRectMake(10, updateItem.indexPathAfterUpdate.item * 310, 300, 44); // or some other initial frame

            UIAttachmentBehavior *springBehaviour = [[UIAttachmentBehavior alloc] initWithItem:attributes attachedToAnchor:attributes.center];

            springBehaviour.length = 1.0f;
            springBehaviour.damping = 0.8f;
            springBehaviour.frequency = 1.0f;
            [self.dynamicAnimator addBehavior:springBehaviour];
        }
    }];
}   

There's one problem with it where it seems to cause a crash when you're at the end of the collection view. Does anyone have any ideas on this problem?

cswelin commented 10 years ago

It seems to be crashing when adding a behaviour that already exists for that indexPath.

To test this, i've added if([self.dynamicAnimator layoutAttributesForCellAtIndexPath:updateItem.indexPathAfterUpdate]) return;

just after the if statement and it stops crashing.

ashfurrow commented 10 years ago

Strange that it's trying to add duplicate index paths. Should we close this issue, then?

cswelin commented 10 years ago

I have no problems with that, seems to be working smoothly if with the added check.

atomkirk commented 10 years ago

Made an addition to update the dynamic animator items and the behaviors when cells are inserted/deleted. https://github.com/TeehanLax/UICollectionView-Spring-Demo/pull/12