I have experiences a similar issue where when running the code using Xcode 16.0 / iOS 18, the app will crash. The trigger point is where instead of dequeueReusableCell, I pull from the previously saved "self.bannerItem" and the app crash with the follow error.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The collection view's data source returned a cell that is in the reuse queue. Cells must be retrieved by calling -dequeueConfiguredReusableCellWithRegistration:forIndexPath:item: or -dequeueReusableCellWithReuseIdentifier:forIndexPath:. Collection view: <UICollectionView: 0x107824200; frame = (0 59; 393 759); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600000c6eca0>; backgroundColor = <UIDynamicSystemColor: 0x600001767040; name = systemBackgroundColor>; layer = <CALayer: 0x600000248c60>; contentOffset: {0, 766.33333333333337}; contentSize: {393, 2340}; adjustedContentInset: {0, 0, 0, 0}; layout: <UICollectionViewFlowLayout: 0x10690c380>; dataSource: <AppTestiOS18.ViewController: 0x10690cd20>>; index path: (0-0); cell: <AppTestiOS18.ItemCollectionViewCell: 0x105707530; baseClass = UICollectionViewCell; frame = (46.6667 1740; 300 600); hidden = YES; layer = <CALayer: 0x60000024e6a0>>'
The actual code can run using Xcode 15.4 and iOS 17 without any issues
class ItemCollectionViewCell:UICollectionViewCell {
static let cellIdentifier = "\(type(of: ItemCollectionViewCell.self))"
}
class ViewController: UIViewController {
struct ContentCellItem {
let height:CGFloat
}
enum ContentSection {
case TopBanner(ContentCellItem)
case FeatureBanner(ContentCellItem)
case Title(ContentCellItem)
case Webconent(ContentCellItem)
case RelatedArticle(ContentCellItem)
}
let dataSrc:[ContentSection] = {
var v:[ContentSection] = []
v.append(.TopBanner(.init(height: 200)))
v.append(.FeatureBanner(.init(height: 300)))
v.append(.Title(.init(height: 400)))
v.append(.Webconent(.init(height: 800)))
v.append(.RelatedArticle(.init(height: 600)))
return v
}()
let collectionView:UICollectionView = {
let t = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
t.register(ItemCollectionViewCell.classForCoder(), forCellWithReuseIdentifier: ItemCollectionViewCell.cellIdentifier)
return t
}()
private var bannerItem:ItemCollectionViewCell!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
view.leadingAnchor.constraint(equalTo: collectionView.leadingAnchor).isActive = true
view.trailingAnchor.constraint(equalTo: collectionView.trailingAnchor).isActive = true
view.safeAreaLayoutGuide.topAnchor.constraint(equalTo: collectionView.topAnchor).isActive = true
view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor).isActive = true
collectionView.layer.borderColor = UIColor.red.cgColor
collectionView.layer.borderWidth = 3.0
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSrc.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let section = dataSrc[indexPath.row]
switch section {
case .TopBanner(_):
if self.bannerItem == nil {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier:ItemCollectionViewCell.cellIdentifier , for: indexPath) as? ItemCollectionViewCell else {
return UICollectionViewCell()
}
self.bannerItem = cell
}
self.bannerItem.layer.borderColor = UIColor.green.cgColor
self.bannerItem.layer.borderWidth = 1.0
return bannerItem
default:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier:ItemCollectionViewCell.cellIdentifier , for: indexPath) as? ItemCollectionViewCell else {
return UICollectionViewCell()
}
cell.layer.borderColor = UIColor.blue.cgColor
cell.layer.borderWidth = 1.0
return cell
}
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellWidth:CGFloat = 300
guard indexPath.row < dataSrc.count else {
return CGSize(width: cellWidth, height: 1)
}
let section = dataSrc[indexPath.row]
switch section {
case .TopBanner(let item):
return CGSize(width: cellWidth, height: item.height)
case.FeatureBanner(let item):
return CGSize(width: cellWidth, height: item.height)
case .Title(let item):
return CGSize(width: cellWidth, height: item.height)
case .Webconent(let item):
return CGSize(width: cellWidth, height: item.height)
case .RelatedArticle(let item):
return CGSize(width: cellWidth, height: item.height)
}
}
}