lionheart / openradar-mirror

A mirror of radars pulled from http://openradar.me/.
245 stars 17 forks source link

34933061: UICollectionView reloads cell after `endInteractiveMovement` #18633

Open openradar-mirror opened 6 years ago

openradar-mirror commented 6 years ago

Description

Summary: Behavior for iOS 11 UICollectionView has changed after endInteractiveMovement() or cancelInteractiveMovement() is called such that it now reloads the cell at the new index path after it is moved/cancelled asynchronously (seemingly triggered from a call to layout subviews in the collection view). Whereas, in iOS 10, the cell did not reload and simply maintained the view it had.

This will at least cause the cell to flash as the layout is invalidated and reloaded.

But the real issue arises when you want to manipulate cells directly after endInteractiveMovement() and change the source data such that a different number of cells exist in the collection than did before the reorder took place. Because the cellForItemAt indexPath call is delayed by the animation, it will try loading the cell after it may have been removed (via deleteItems(at:)) Then you get a crash.

Steps to Reproduce:

  1. Create a UICollectionView.
  2. Implement the interactive movement methods with a LongPressGestureRecognizer.
  3. Run the app.
  4. Press and hold to drag. When the drag completes the moved cell will flash and reload.

Expected Results: The cell should move to it's new location seamlessly in it's new state with no view flashing.

Actual Results: The view flashes as the cell is removed and laid out again.

Version/Build: iOS 11 (15A372)

- Product Version: iOS 11 Created: 2017-10-11T14:46:15.438880 Originated: 2017-10-11T00:00:00 Open Radar Link: http://www.openradar.me/34933061

ctjalsma commented 6 years ago

I have observed that a new cell is actually created to take the place of the moving cell. This goes against the re-use principal entirely! Thanks for filing this. A workaround in progress...

// UICollectionView subclass
@synthesize cellInMotion; //  a property set by the controller when the move starts
- (UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath{
    if(cellInMotion){
        return cellInMotion;
    }
    UICollectionViewCell *queueCell;
    do{
        queueCell = [super dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
    } while ([queueCell isEqual:cellInMotion]);
    return queueCell;
}
fysteven commented 5 years ago

Is this still an open issue in iOS 12?

pomozoff commented 5 years ago

@fysteven, yes, collection view in iOS 12 reloads an item when it was moved or a moving is canceled.