2020/9/11 突然在 Firebase Crashlytics 上接到為數不少的閃退錯誤訊息:

Fatal Exception: NSInternalInconsistencyException

the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath (UICollectionElementKindSectionHeader,<NSIndexPath: 0x850daa46ec075df5> {length = 2, path = 3 – 0}) was not retrieved by calling -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: or is nil (<UICollectionReusableView: 0x141920c10; frame = (0 0; 0 0); layer = <CALayer: 0x2823a5100>>)

奇怪的是在 9/11 以前一個閃退記錄都沒有,不知道是不是 Crashlytics team 有針對抓錯系統做了某些調整讓這個錯誤可以被抓出來。

稍微研究了一下發現是 UICollectionReusableView 搞的鬼,

collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) 裡必須要使用 collectionView.dequeueReusableSupplementaryView 來建立 UICollectionReusableView,

也就是你不能直接 return UICollectionReusableView()。

如果是遇到需要回傳空白的 collection reusable view,可以建立一個自訂的 EmptyCollectionReusableView:

class EmptyCollectionReusableView: UICollectionReusableView {
}

view raw
.swift
hosted with ❤ by GitHub

記得 collection view 要註冊 EmptyCollectionReusableView:

collectionView.register(EmptyCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "empty")

view raw
.swift
hosted with ❤ by GitHub

在需要空 header/footer 的地方回傳 EmptyCollectionReusableView:

return collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "empty", for: indexPath)

view raw
.swift
hosted with ❤ by GitHub