CollectionView 因无效 Header 而崩溃

Crash in CollectionView For Invalid Header

我想了解这个错误是什么意思?

 *** Terminating app due to uncaught exception   'NSInternalInconsistencyException', reason: 
'the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath: was not 
retrieved by calling -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: 
for element kind 'UICollectionElementKindSectionHeader' at index path <NSIndexPath: 0x8aeb905cf5be0ed2> 
{length = 2, path = 0 - 0}; supplementary view: 
<UICollectionReusableView: 0x7f9236dc4ff0; frame = (0 0; 0 0); layer = <CALayer: 0x600001018620>>'

我正在为 UICollectionView.I 使用自定义 header 我在加载视图后立即发生崩溃。甚至在调用 cellforrowatindexpath 之前,问题不在于自定义 header,而在于 return UICollectionReusableView()

func collectionView(_ collectionView: UICollectionView,   viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    
    if kind == UICollectionView.elementKindSectionHeader  && indexPath.section == 2      
    { 
     return someCustomHeader
    }
    
    return UICollectionReusableView()
}
    

当您使用自定义 header 时,您必须先注册 header class。

  collectionView.register(AppHeaderCollectionView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: AppHeaderCollectionView.headerIdentifier)

然后要使用 header 你必须这样做。

 override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: AppHeaderCollectionView.headerIdentifier, for: indexPath) as! AppHeaderCollectionView
        return header
    }

您必须始终使用方法 dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: 获取 header 部分,在调用它之前您还必须注册一个 header class。如果您只想显示第三部分的 header,您必须实施 collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) 以隐藏不需要的 header,方法是给它们一个 .zero 大小(您不能简单地 return 一个 UICollectionReusableView 的实例用于不需要的 headers).

import UIKit

class CollectionViewController: UICollectionViewController {
   private let headerId = "headerId"

   override func viewDidLoad(){
      super.viewDidLoad()

      // Registers a header class
      self.collectionView.register(YourClass.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: self.headerId)  // Replace YourClass with the name of your header class
   }

   func collectionView(_ collectionView: UICollectionView,   viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
      // This method must always call dequeueReusableSupplementaryView, even if section!=2
      if kind == UICollectionView.elementKindSectionHeader{ 
         return self.collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: self.headerId, for: indexPath)
      }

      return UICollectionReusableView()
    }
   
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize{
       // Shows only the header of the third section
       return section == 2 ? desiredSize : .zero  // Replace desiredSize with the size of the visible header
    }
}