Crash in iOS18

I have a UITableView which contains a UICollectionView in the first row. It used to work fine in iOS17, but now I get a crash when running with Xcode 16 / iOS18 beta:

Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:]

This is my UITableView delegate call:

    AddEditDataCell *cell = nil;
    if (indexPath.section == 0) {
        
        if (indexPath.row == 0) {
            AddEditDataContactsCell *contactNameCell = (AddEditDataContactsCell *)[self cellForContactNamesCollectionAtIndexPath:indexPath tableView:tableView];
            return contactNameCell; 


- (AddEditDataContactsCell *)cellForContactNamesCollectionAtIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView {
    AddEditDataContactsCell *contactsCell = (AddEditDataContactsCell *)[self.tableView dequeueReusableCellWithIdentifier:@"ContactsCell" forIndexPath:indexPath];
    if (self.collectionNameCell == nil) {
        self.collectionNameCell = [contactsCell.collectionView dequeueReusableCellWithReuseIdentifier:@"LogContactNameCollectionCellIdentifier" forIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
        contactsCell.nameCellDelegate = self;
    }

    contactsCell.frame = CGRectZero;
    [contactsCell setNeedsLayout];
    [contactsCell.collectionView reloadData];
    
    contactsCell.collectionViewHeightConstraint.constant = contactsCell.collectionView.collectionViewLayout.collectionViewContentSize.height;
    
    [contactsCell.collectionView.collectionViewLayout invalidateLayout];
    return contactsCell;
}

@zulfishah Could you create a test project and share a link to the project. I'd be happy to take a look. Creating a test project, goes over the criteria for a focused test project.

We had a similar issue. Turns out we were calling dequeReusableCellWithIdentifier: to create a cell in another method which we used for size estimates, and it seems like on ios 18 the UICollectionView really does not like that. If you deque a cell it expects you to give it that cell, eg in response to cellForItemAtIndexPath.

Changing that other cell creation to just alloc/init fixed the crash for us.

Try "self.collectionNameCell = [ .... alloc] init];" instead of deque.

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)
        }
    }
}

I had similar issue with iOS18.(issue exists in below code)

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FTShelfTagsPageCell", for: indexPath) as? FTShelfTagsPageCell else { return UICollectionViewCell() } cell.selectionBadge?.isHidden = viewState == .none ? true : false

    if indexPath.section == 0 {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FTShelfTagsBooksCell", for: indexPath) as? FTShelfTagsBooksCell else {
            return UICollectionViewCell()
        }
        return cell
    } else if indexPath.section == 1 {
        let item = pages[indexPath.row]
        cell.updateTagsItemCellContent(tagsItem: item, isRegular: self.traitCollection.isRegular)
    }
    cell.isSelected = true
    return cell
}

It is dequeuing 2 cells though I return single cell.

After simplification like below, issue got fixed. (only 1 cell ll be dequeued at a time.)

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if indexPath.section == 0 {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FTShelfTagsBooksCell", for: indexPath) as? FTShelfTagsBooksCell else {
            return UICollectionViewCell()
        }
        return cell
    } else  {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FTShelfTagsPageCell", for: indexPath) as? FTShelfTagsPageCell else {
            return UICollectionViewCell()
        }
        let item = pages[indexPath.row]
        cell.selectionBadge?.isHidden = viewState == .none ? true : false
        cell.updateTagsItemCellContent(tagsItem: item, isRegular: self.traitCollection.isRegular)
        cell.isSelected = true
        return cell
    }
}

Can confirm that I had this issue and did exactly what @Narayana-M_7 did, I was dequeuing two times for the same returned cell. Once I made sure there is only one dequeueing happening, the crash vanished.

I came across this crash as well. It seemed to be because we were manually dequeuing supplementary view in the func collectionView(collectionView:layout:referenceSizeForHeaderInSection:) -> CGSize.

Once I found a way to use supplementaryView instead of dequeueReusableSupplementaryView, the issue was resolved

let headerView = collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionHeader, at: indexPath)

Xcode 16 was also complaining/suggesting to use dequeueConfiguredReusableSupplementary instead of dequeueReusableSupplementaryView(ofKind:withReuseIdentifier:for:).

We had a mix of iOS 14+ registration APIs for regular cells but older registration style for supplementary views. I updated to use UICollectionView.SupplementaryRegistration at the same time, which might've helped the issue as well

Hope these help

I've the same problem, but as far I can see I don't dequeue twice. Can someone help me out here?

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "NieuwsCollectionViewControllerCell", for: indexPath) as! NieuwsCollectionViewCell
                
        let feedRow = MyNewsLoader.shared.returnNews()[indexPath.row]
        
        let feedTitle = feedRow.title
        let feedDescription = feedRow.description?.trimHTMLTags()
        let feedLink = feedRow.link
        
        cell.feedTitle?.text = feedTitle
        cell.feedDescription?.text = feedDescription
              
        return cell
            
    }

What going wrong here?

indeed, for my case, iOS18 the crash point is here,,,

  • more than 1 dequeue
  • fix by recheck logic/code-flow
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> MyCell {
 
 	let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? MyCell
 	let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? MyCell
 	let cell3 = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? MyCell
 	let cell4 = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? MyCell

return cell1
}

We are also experiencing an app crash issue in the viewForSupplementaryElementOfKind method:

func collectionView(_ collectionView: UICollectionView,

                    viewForSupplementaryElementOfKind kind: String,

                    at indexPath: IndexPath) -> UICollectionReusableView {

    switch kind {

    case UICollectionView.elementKindSectionHeader:

        let headerView = collectionView.dequeueReusableSupplementaryView(

            ofKind: kind,

            withReuseIdentifier: headerViewIdentifier, for: indexPath)

        return headerView

    case UICollectionView.elementKindSectionFooter:

        let footerView = collectionView.dequeueReusableSupplementaryView(

            ofKind: kind,

            withReuseIdentifier: footerViewIdentifier, for: indexPath)

        return footerView
   default:
        break
    }
}

As @KSmith95 mentioned, we also tried using supplementaryView, but it always returns nil and leading the app crash.

In case this helps anyone else. I was seeing the same crash. I eventually solved it by setting a symbolic break point on:

-[UICollectionView dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:]

Turns out the app was dequeuing a cell to calculate size elsewhere in the app.

We came across this same crash recently, but it was slightly different to all the above cases I think, so hopefully this helps someone.

We were actually already using cellForItemAtIndexPath: rather than directly dequeuing a cell, but were calling the UICollectionViewDataSource's implementation in our viewController instead of directly on the UICollectionView, and so of course calling the data-source's method will in turn call dequeueReusableCell e.g.

[self collectionView:self.collectionView cellForItemAtIndexPath:indexPath];

instead of:

[self.collectionView cellForItemAtIndexPath:indexPath];

Changing to the latter fixed the issue.

Our app had the same crash. We were trying to access a mockCell used for calculating the height of the cell before the collection view was accessible. After some research, we realized we don't need the heightForContent() anymore. Here is the code change:

❌ Before:

func size(for indexPath: IndexPath) -> CGSize {
  let mockCell = settingItemCell(collectionView, indexPath: indexPath) as? SettingButtonCell {
                height = mockCell.heightForContent(withWidth: contentWidth)
}

✅ After:

func size(for indexPath: IndexPath) -> CGSize {
  height = 40
}

The following line was causing the crash: let mockCell = settingItemCell(collectionView, indexPath: indexPath) as? SettingButtonCell

Can anyone help me to resolve this issue? I have two collectionviews in a tableview and each time you try to scroll the collecctionview after clicking a cell, it crashes with the following error:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:]

I'm using

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! NearbyNTOcolViewCell

I am gettin same error but I cant figure out whats wrong here. The above solutions dont even apply because I have only 1 cell to dequeue. It was working until I upgraded to iOS 18 / Xcode 16

I am using UICollectionViewCompositionalLayout for estimated height and 1.0 fractional width.

Theres only 1 section in the collection view with 7 items in that section. And again, only one line of collectionView.dequeueReusableCell.

When I run, the first two cell display fine, but the moment I scroll to load more cells, its breaks with below error.

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:]

My case doesn't fall under all these. I've multiple collectionviews in my storyboard and assigned delegate & datasource to my class there and over riding the same in my class via code. Now when i remove all those unnessary datasource & delegates in storyboard, its working fine.

I'm getting a crash for decoration views somewhere inside UIKitCore which is definitely out of my control – the code doesn't dequeue or care about instantiation of decoration views at all – all it does is inserting the registered layout attributes in the flow layout subclass, the rest of it (instantiation of the registered view & queuing/dequeuing) is provided by UIKit.

I have a ton of crashes starting with iOS 18, not a single one on iOS 17 and prior. Call stack:

Thread 1: "*** -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 3]"

#1	0x000000018039c67c in -[__NSArrayM objectAtIndex:] ()
#2	0x0000000185a9aa54 in -[_UICollectionViewSubviewManager dequeueReusableViewWithReuseIdentifier:elementKind:elementCategory:] ()
#3	0x00000001851bc3cc in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:] ()
#4	0x00000001851a6ab4 in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:layout:withLayoutAttributes:applyAttributes:] ()
#5	0x00000001851af69c in -[UICollectionView _createVisibleViewsForSingleCategoryAttributes:limitCreation:fadeForBoundsChange:] ()
#6	0x00000001851af824 in -[UICollectionView _createVisibleViewsForAttributes:fadeForBoundsChange:notifyLayoutForVisibleCellsPass:] ()
#7	0x00000001851ad9c4 in -[UICollectionView _updateVisibleCellsNow:] ()

Array index out of bounds. Definitely not an array in reach, very internal operations. This is also preceded by the following warning thrown into Console:

UICollectionView internal inconsistency: attempted to queue view that is already in the reuse queue. Collection view: <TripItineraryDayCollectionView: 0x146917400; baseClass = UICollectionView; frame = (0 0; 402 682); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600000e5d770>; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x600000393440>; contentOffset: {0, 0}; contentSize: {402, 662}; adjustedContentInset: {0, 0, 0, 0}; layout: <TripItineraryDayViewLayout: 0x1463d6770>; dataSource: <TripItineraryDayView: 0x1463d6360; frame = (0 102; 402 682); clipsToBounds = YES; autoresize = W+H; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x6000003974a0>>>; view: <TransportLineDecorationView: 0x1059e51a0; baseClass = UICollectionReusableView; frame = (14 257; 54 69); userInteractionEnabled = NO; layer = <CALayer: 0x6000004180c0>>; layout attributes: <TransportDecorationViewLayoutAttributes: 0x1463e34a0; index path: (2-4); element kind: (TripItineraryDayTransportDecorationView); frame = (14 257; 54 69)>

Disabling the decoration views makes the crash go away.

Something has probably changed in iOS 18 which might have sense for cells (where providing the views in the delegate properly is mandatory) or supplementary views, yet it doesn't work really well with decoration views. It gives me the impression that supplementary and decoration views have been merged into one queue stack internally, but something's not right.

I had similar issue with iOS18.(issue exists in below code)

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCollectionViewCell.collectionTextCell.rawValue, for: indexPath) as? CollectionTextCell else {

        return UICollectionViewCell()

    }

    cell.isDetailPage = isFromDetailPage

    cell.manageFocus(isFocusSelected: isSelectedFocus == indexPath.row)

    switch detailComponentType[indexPath.row] {

    case .episodes, .trailer, .morelikethis, .castcrew, .OtherChannelsLive, .recommendeLivechannelsforyou, .similarContentLive, .highlightsSports, .otherTournaments, .readMore, .playlist:

        cell.manageData(data:  detailComponentType[indexPath.row])

    case .bestOfProvider: cell.textlbl.text = Constant.bestOfProvider + /content_Data?.where_to_watch?.first?.provider?.name

    case .otherSportsType: cell.textlbl.text = Constant.otherSportsType + /content_Data?.format + " " + Constant.tournaments

    }

    return cell

}

I am getting the same crash but my use case shouldn't be triggering the crash by Apple's description.

In my case, I have a custom function to dynamically calculate cell sizes defined as:

public func intrinsicCellSize(
        forCellAtIndexPath indexPath: IndexPath,
        width: CGFloat? = nil,
        height: CGFloat? = nil
    ) -> CGSize {
        guard let dataSource = dataSource else {
            return .zero
        }
        let cell = dataSource.collectionView(self, cellForItemAt: indexPath)
        
        if let cell = cell as? HeightProvidingCell, let width {
            return .init(width: width, height: cell.provideHeight(for: width))
        }

        let targetSize = CGSize(
            width: width ?? UIView.layoutFittingExpandedSize.width,
            height: height ?? UIView.layoutFittingExpandedSize.height
        )
        let size = cell.contentView.systemLayoutSizeFitting(
            targetSize,
            withHorizontalFittingPriority: .fittingSizeLevel,
            verticalFittingPriority: .fittingSizeLevel
        )
        return size
    }

I call this in the sizeForItemAt delegate function. This was working flawlessly before updating macOS and Xcode but now this crashes. Specifically, it crashes with the call

let cell = dataSource.collectionView(self, cellForItemAt: indexPath)

By Apple's error message, this should be fine as I'm not calling deque, the error message even suggests that you use this method.

Perhaps the issue is the order in which UIKit calls the delegate and dataSource methods. By adding print statements, I discovered that sizeForItemAt is called before cellForItemAt so in my case, the flow of function calls is:

  • sizeForItemAt (Called by UIKit)
  • cellForItemAt (Called by me)
  • cellForItemAt (Called by UIKit)

Perhaps UIKit is expecting the first call of cellForItemAt to be made by UIKit and not the user. If this is the case, my app is broken since I relied heavily on this

I just want to provide a solution that I've found for our use case. We had the following:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: someCellId,
            for: indexPath
        ) as! SomeCollectionViewCell

        // some logic
        return cell

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: someCellId,
            for: indexPath
        ) as! SomeCollectionViewCell

        // some more logic
}

I have changed the above code to the below, which fixed the crash.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: someCellId,
            for: indexPath
        ) as! SomeCollectionViewCell

        // some logic
        return cell

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cell = collectionView.cellForItem(at: indexPath) as? SomeCollectionViewCell

        // some more logic
}

As you can see, we were using the dequeueReusableCell function twice, which caused the crash. Using it only once fixed it for us.

I also encountered the crash problem. This is the original code:

  • (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { HomeCellUnconnected *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellClassNameUnconnected forIndexPath:indexPath];

    if (self.datas.count > indexPath.row) { NSString *cellClassName = self.datas[indexPath.row]; cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellClassName forIndexPath:indexPath]; }

    return cell;

}

this is the modified code:

  • (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { NSString *cellClassName = self.datas[indexPath.row]; UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellClassName forIndexPath:indexPath];

    return cell;

}

There is a site that analyzes and resolves the issue; please refer to it.

https://rldd.tistory.com/696

For anyone using IGListKit:

The issue is exactly as stated: a cell or supplementaryView is being dequeued more than once which results in a crash on iOS 18.

I found the issue in one of our ListSectionController objects.

final class MySectionController: ListSectionController {
  // ...
  override func cellForItem(at index: Int) -> UICollectionViewCell {
    guard let cell = collectionContext?.dequeueReusableCell(of: MyCell.self, for: self, at: index) as? MyCell else {
      return UICollectionViewCell()
    }
    // ...
    return cell
  }
}

 // ... elsewhere:
 let sourceView = cellForItem(at: 0)

That last line mistakenly calls cellForItem on the section controller instead of the collectionContext.

To fix:

let sourceView = collectionContext?.cellForItem(at: 0, sectionController: self)

Hi all, I have this problem - Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:].

My code crashed just IOS18+

My code -

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
      guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SectionModsCell.cellIndetifire, for: indexPath) as? SectionModsCell else { return UICollectionViewCell() }
        
        switch mainState {
        case .main:
            
            if ApphudManager.sharedInstance.isPremium {
                let cellData = sectionModsData[indexPath.item]
                return cell.setupCell(data: cellData)
            } else {
                let newIndex = getIndex(for: indexPath)
                
                
                guard indexPath.item != adIndexPath || adIndexPath == 0 else {
                    if UIDevice.current.userInterfaceIdiom == .pad {
                        let bannerCell = collectionView.dequeueReusableCell(withReuseIdentifier: IpadNativeCell.cellIndetifire, for: indexPath) as! IpadNativeCell
                        bannerCell.setupCell(nativeAd: nativeAd)
                        return bannerCell
                    } else {
                        let bannerCell = collectionView.dequeueReusableCell(withReuseIdentifier: SmallNativeCell.cellIndetifire, for: indexPath) as! SmallNativeCell
                        bannerCell.setupCell(nativeAd: nativeAd)
                        return bannerCell
                    }
                }
                
                let cellData = sectionModsData[newIndex]
                return cell.setupCell(data: cellData)
            }
            
        case .search:
            let cellData = filteredModsData[indexPath.item]
            return cell.setupCell(data: cellData)
        }

    }

And this code not give me error, my mind is blow (

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
        
        switch mainState {
        case .main:
            
            if ApphudManager.sharedInstance.isPremium {
                
                guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SectionModsCell.cellIndetifire, for: indexPath) as? SectionModsCell else { return UICollectionViewCell() }
                
                let cellData = sectionModsData[indexPath.item]
                return cell.setupCell(data: cellData)
            } else {
                let newIndex = getIndex(for: indexPath)
                
                
                guard indexPath.item != adIndexPath || adIndexPath == 0 else {
                    if UIDevice.current.userInterfaceIdiom == .pad {
                        let bannerCell = collectionView.dequeueReusableCell(withReuseIdentifier: IpadNativeCell.cellIndetifire, for: indexPath) as! IpadNativeCell
                        bannerCell.setupCell(nativeAd: nativeAd)
                        return bannerCell
                    } else {
                        let bannerCell = collectionView.dequeueReusableCell(withReuseIdentifier: SmallNativeCell.cellIndetifire, for: indexPath) as! SmallNativeCell
                        bannerCell.setupCell(nativeAd: nativeAd)
                        return bannerCell
                    }
                }
                
                guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SectionModsCell.cellIndetifire, for: indexPath) as? SectionModsCell else { return UICollectionViewCell() }
                
                let cellData = sectionModsData[newIndex]
                return cell.setupCell(data: cellData)
            }
            
        case .search:
            
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SectionModsCell.cellIndetifire, for: indexPath) as? SectionModsCell else { return UICollectionViewCell() }
            
            let cellData = filteredModsData[indexPath.item]
            return cell.setupCell(data: cellData)
        }

    }

My code

extension MyViewController: UICollectionViewDelegate, UICollectionViewDataSource {
    
    func collectionView(
        _ collectionView: UICollectionView,
        cellForItemAt indexPath: IndexPath
    ) -> UICollectionViewCell {
        if let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: "CollectionViewCellID",
            for: indexPath
        ) as? CollectionViewCell {
            cell.setup()
            return cell
        }
        return UICollectionViewCell()
    }
    
    func collectionView(
        _ collectionView: UICollectionView,
        didSelectItemAt indexPath: IndexPath
    ) {
        // Unnecessary dequeue
        guard collectionView.dequeueReusableCell(
            withReuseIdentifier: "CollectionViewCellID",
            for: indexPath
        ) is CollectionViewCell else { return }
        // My action for selecting cell
        print("Cell Selected")
    }
}

Error:


*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:].

Solution:

The problem was doing unnecessary dequeuing in didSelectItemAt when selecting the cell. In previous iOS like 17 or 16 or lower, it was allowed to dequeue where it is not really needed but from iOS 18, it may restricted to unnecessary dequeuing. So better to remove dequeue and use cellForItem(at) if we need to get cell from collection view.

Example

extension MyViewController: UICollectionViewDelegate, UICollectionViewDataSource {
    
    func collectionView(
        _ collectionView: UICollectionView,
        cellForItemAt indexPath: IndexPath
    ) -> UICollectionViewCell {
        if let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: "CollectionViewCellID",
            for: indexPath
        ) as? CollectionViewCell {
            cell.setup()
            return cell
        }
        return UICollectionViewCell()
    }
    
    func collectionView(
        _ collectionView: UICollectionView,
        didSelectItemAt indexPath: IndexPath
    ) {
        guard collectionView.cellForItem(at: indexPath) is CollectionViewCell else { return }
        // My action for selecting cell
        print("Cell Selected")
    }
}

I Found out some situation will be crash in iOS 18.

When u want to get cell or header(footer) by calling dequeueCell or dequeueSupplementaryView. And which isn't in collectionView dataSource function like, 'cellForRow' or viewForSupplementaryElementOfKind, It will be crash!!!

So, if u have a function call getFootView() like below:

    func getFootView(indexPath: IndexPath) -> RangePriceFootView? {
        return collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "FOOTER", for: indexPath)
    }

Call this function at viewForSupplementaryElementOfKind, it is legal.

   func collectionView(
        _ collectionView: UICollectionView,
        viewForSupplementaryElementOfKind kind: String,
        at indexPath: IndexPath
    ) -> UICollectionReusableView {
        let footer = getFootView(indexPath: indexPath)
        // footer do something
        return footer
    }

but if u call this from other place than viewForSupplementaryElementOfKind, it will be crash

   func updateUI() {
        let footer = getFootView(indexPath: indexPath)
        // do something
    }

This warning below tell us, call use -[UlCollectionView cellFortemAtindexPath:] or -[UlCollectionView supplementaryViewForElementKind:atIndexPath:] when u are not in config function.

Thread 1: "Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UlCollectionView cellForltemAtindexPath:] or -[UlCollectionView supplementaryViewForElementKind:atindexPath:].
Crash in iOS18
 
 
Q