0

I want to show my data in collections view.

I have a UICollectionView and I set the cellForItemAt delegate method. Here is the code I've tried in cellForItemAt delegate method.

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

Edit Code (All of cellForItemAt Delegate Method):

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

        let productSnapshot = products[indexPath.item]

        if let productsDictionary = productSnapshot.value as? NSDictionary{
            guard let productName = productsDictionary["name"] as? String else { return UICollectionViewCell() }
            guard let productPrice = productsDictionary["price"] as? Int else { return UICollectionViewCell() }
            guard let productCategory = productsDictionary["category"] as? String else { return UICollectionViewCell() }

            let product = Product(uid: productSnapshot.key, name: productName, price: productPrice, categoryUid: productCategory)

            cell.setProduct(product: product)
        }

        return cell

    }

This is the error message:

"Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier - cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:'"

  • Can you include the implementation of your collectionView(cellForItemAtIndexPath:) function? Or is that line all of it? – Michael Fourre Sep 25 '19 at 20:15
  • Is that the only code that you have in that function? Can you edit the question to show that delegate function In its entirety? The code you have shown isn't consistent with the exception message – Paulw11 Sep 25 '19 at 20:16
  • 1
    I edited the code. @Paulw11 – redwheelbarrow Sep 25 '19 at 20:24

1 Answers1

0

Your problem is caused by all of those guard/else statements - If any of the guards fail then you return UICollectionViewCell() - Which, as the exception says, is a cell that was not dequeued correctly.

Really, your data model should have been validated before it got to this point. products should contain instances of Product rather than a Dictionary. This way you never load the invalid products into the data source array.

Once you do that you can simply write

var products: [Product]

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

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

    let product = products[indexPath.item]
    cell.setProduct(product: product)

    return cell

}

Remember that cellForItemAt: may be called many times for a given item as the collection view scrolls - It should be as efficient as possible. Although there isn't a huge overhead in accessing the dictionary and creating the Product there is no need to do it again and again.

Paulw11
  • 108,386
  • 14
  • 159
  • 186