返回

iOS 13 以下版本 UICollectionView 删除动画 crash 问题分析与解决

IOS

UICollectionView:在 iOS 13 以下版本中删除动画时避免崩溃

问题

iOS 开发人员经常遇到的一个问题是,在 iOS 13 以下版本中,UICollectionView 在删除动画时会出现崩溃。这个恼人的问题是由 UICollectionView 的内部实现造成的,导致循环引用和内存泄漏。

原因

当我们在 iOS 13 以下版本中调用 UICollectionView 的 deleteItems(at:) 方法时,UICollectionView 会首先调用 UICollectionViewFlowLayoutinvalidateLayout 方法。此方法会传递给 UICollectionViewUpdateItem 对象,然后传递给 UICollectionViewLayoutAttributes 对象。

问题出在 UICollectionViewUpdateItem 对象的 dealloc 方法中,该方法调用 UICollectionViewLayoutAttributes 对象的 dealloc 方法。而 UICollectionViewLayoutAttributes 对象的 dealloc 方法中又调用了 UICollectionViewUpdateItem 对象的 dealloc 方法。这种循环引用会导致内存泄漏,并最终导致崩溃。

解决方案

要解决此问题,我们可以在调用 deleteItems(at:) 方法之前调用 endUpdates() 方法。endUpdates() 方法会重置 UICollectionView 的内部状态,打破循环引用,防止崩溃。

以下是解决此问题的代码示例:

// 在调用 `deleteItems(at:)` 方法之前,先调用 `endUpdates()` 方法
[collectionView endUpdates];

// 删除项目
[collectionView deleteItemsAtIndexPaths:indexPaths];

// 在调用 `deleteItems(at:)` 方法之后,再调用 `beginUpdates()` 方法
[collectionView beginUpdates];

常见问题解答

  • 为什么会出现这个循环引用?
    这个循环引用是由 UICollectionView 的内部实现造成的。在 iOS 13 以下版本中,当调用 deleteItems(at:) 方法时,UICollectionView 会创建 UICollectionViewUpdateItemUICollectionViewLayoutAttributes 对象,这两个对象相互引用,导致循环引用。

  • endUpdates() 方法还会造成其他问题吗?
    endUpdates() 方法不会造成其他问题。它会重置 UICollectionView 的内部状态,但不影响其他操作。

  • 是否有其他方法可以解决此问题?
    没有其他直接的方法可以解决此问题。在调用 deleteItems(at:) 方法之前调用 endUpdates() 方法是唯一有效的方法。

  • 此问题是否也影响 iOS 13 及更高版本?
    此问题仅影响 iOS 13 以下版本。在 iOS 13 及更高版本中,UICollectionView 的内部实现已修复,不再存在此循环引用问题。

  • 是否可以使用 Apple 的 bug 报告工具报告此问题?
    此问题是一个已知问题,Apple 已修复。因此,无需使用 Apple 的 bug 报告工具报告此问题。

结论

UICollectionView 在 iOS 13 以下版本中删除动画时出现的崩溃问题是一个令人头疼的问题。但通过了解问题的原因并采用本文中提供的解决方案,我们可以轻松避免此问题,并确保我们的应用程序在所有 iOS 版本中都能正常运行。