iOS 15 - UICollectionView 崩溃 - 尝试使用在 -collectionView:cellForItemAtIndexPath: 内部创建的注册使单元格出列:

Ser*_*ost 4 ios uicollectionview swift

这是错误:


线程 1:“尝试使用在 -collectionView:cellForItemAtIndexPath: 或 UICollectionViewDiffableDataSource 单元格提供程序内创建的注册使单元格出列。每次请求单元格时创建新的注册将阻止重用,并导致创建的单元格在内存中保持不可访问状态在集合视图的生命周期内。应预先创建注册并重复使用。注册:<UICollectionViewCellRegistration:0x60000135b300>”


这是导致错误的文件:

import UIKit

class PetExplorerViewController: UICollectionViewController {
  // MARK: - Properties
  var adoptions = Set<Pet>()
  
  lazy var dataSource = makeDataSource()

  // MARK: - Types
  enum Section: Int, CaseIterable, Hashable {
    case availablePets
    case adoptedPets
  }
  typealias DataSource = UICollectionViewDiffableDataSource<Section, Item>

  // MARK: - Life Cycle
  override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = "Pet Explorer"
    configureLayout()
    applyInitialSnapshots()
  }

  // MARK: - Functions
  
  func configureLayout() {
    let configuration = UICollectionLayoutListConfiguration(appearance: .grouped)
    collectionView.collectionViewLayout = UICollectionViewCompositionalLayout.list(using: configuration)
  }
  
  func applyInitialSnapshots() {
    var categorySnapshots = NSDiffableDataSourceSnapshot<Section, Item>()
    
    let categories = Pet.Category.allCases.map { category in
      return Item(title: String(describing: category))
    }
    
    categorySnapshots.appendSections([.availablePets])
    categorySnapshots.appendItems(categories, toSection: .availablePets)
    dataSource.apply(categorySnapshots, animatingDifferences: false)
  }
  
  func makeDataSource() -> DataSource {
    return DataSource(collectionView: collectionView) {collectionView, indexPath, item in
      return collectionView.dequeueConfiguredReusableCell(using: self.categoryCellRegistration(), for: indexPath, item: item)
    }
  }

  
}

// MARK: - CollectionView Cells
extension PetExplorerViewController {
}

// MARK: - UICollectionViewDelegate
extension PetExplorerViewController {
  override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  }

  func pushDetailForPet(_ pet: Pet, withAdoptionStatus isAdopted: Bool) {
    let storyboard = UIStoryboard(name: "Main", bundle: .main)
    let petDetailViewController =
      storyboard.instantiateViewController(identifier: "PetDetailViewController") { coder in
        return PetDetailViewController(coder: coder, pet: pet)
      }
    petDetailViewController.delegate = self
    petDetailViewController.isAdopted = isAdopted
    navigationController?.pushViewController(petDetailViewController, animated: true)
  }
}

// MARK: - PetDetailViewControllerDelegate
extension PetExplorerViewController: PetDetailViewControllerDelegate {
  func petDetailViewController(_ petDetailViewController: PetDetailViewController, didAdoptPet pet: Pet) {
    
  }
  
  func categoryCellRegistration() -> UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
    
    return .init  { cell, _, item in
      var configuration = cell.defaultContentConfiguration()
      configuration.text = item.title
      cell.contentConfiguration = configuration
    }
  }
  
}
Run Code Online (Sandbox Code Playgroud)

我认为这应该是所需要的全部,但更愿意添加故障排除所需的任何其他相关内容。

Tar*_*agi 7

添加此内容是iOS 15为了警告您不要滥用 API。这里有一个解释——

在 iOS 15 上使用注册使单元格出队时,UICollectionView 引发异常

iOS 15即使您非常小心地只创建每种类型的注册一次(例如,通过将它们存储在惰性属性中),也不支持在单元提供程序内创建注册。但解决方法很简单:只需确保在请求任何单元格之前创建您的注册即可。

这是你应该做的 -

// Remove following -
/*
func categoryCellRegistration() -> UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
    
    return .init  { cell, _, item in
      var configuration = cell.defaultContentConfiguration()
      configuration.text = item.title
      cell.contentConfiguration = configuration
    }
  }
*/

// Add following
let categoryCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { cell, _, item in 
    var configuration = cell.defaultContentConfiguration()
    configuration.text = item.title
    cell.contentConfiguration = configuration
}

// Update this line -
// `categoryCellRegistration` is not a function anymore
return collectionView.dequeueConfiguredReusableCell(using: self.categoryCellRegistration, for: indexPath, item: item)
Run Code Online (Sandbox Code Playgroud)