Where am I going wrong?

Hi,

So I basically want to load data from an remote API and I have set all the files up etc but I am having trouble on the data snapshot part of the collection view to load the products as a list view.

Please see the code below.

import UIKit



class ViewController: UIViewController {

    

    enum Section {

        case main

    }

    

    var collectionView: UICollectionView!

    var dataSource: UICollectionViewDiffableDataSource<Section,Product>?

    

    

    

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view.

        

        navigationItem.title = "Products"

        // configureHierarchy()

        //configureDataSource()

        

        collectionView.register(ListCell.self, forCellWithReuseIdentifier: "ListCell")

        

    }

    

    func configure<T: SelfConfiguringCell>(with product: Product, for indexPath: IndexPath) -> T {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ListCell", for: indexPath) as? T else {

            fatalError("Unable to dequeue Cell")

        }

        cell.configure(with: product)

        return cell

    }

    

}



extension ViewController {

    private func createLayout() -> UICollectionViewLayout {

        let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)

        return UICollectionViewCompositionalLayout.list(using: config)

    }

}









extension ViewController {

    private func configureHierarchy() {

        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())

        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        view.addSubview(collectionView)

        collectionView.delegate = self

    }

    

    

    

    private func configureDataSource() {

        

        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Product> { (cell, indexPath, product) in

            var content = cell.defaultContentConfiguration()

            content.text = "\(product.name)"

            cell.contentConfiguration = content

        }

        

        dataSource = UICollectionViewDiffableDataSource<Section, Product>(collectionView: collectionView) {

            (collectionView: UICollectionView, indexPath: IndexPath, identifier: Product) -> UICollectionViewCell? in

            return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)

        }

        

        //inital data

       

        var snapshot = NSDiffableDataSourceSnapshot<Section, Product>()

        snapshot.appendSections([.main])

        snapshot.appendItems([Product], toSection: .main)

        dataSource?.apply(snapshot, animatingDifferences: false)

        

    }

    

}







extension ViewController: UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        collectionView.deselectItem(at: indexPath, animated: true)

    }

}

My API doesn't have separate sections hence why I used an enum to define one but where am I going wrong appending items to the section?

Best, Imran

It's unclear exactly what problem you're asking about, but the following line of code is incorrect:

        snapshot.appendItems([Product], toSection: .main)

You need an array of Product items as the first parameter, and [Product] is a type, not a value. Are you asking how to get products from (e.g.) a server, in order to add them to the collection view?

If the array of products is not yet available at the time when viewDidLoad executes, you'll need to fetch them asynchronously. One approach might be to set up your initial snapshot with an empty array:

        snapshot.appendItems([], toSection: .main)

Then, from viewDidLoad start an asynchronous fetch of the products from your server. When that's done, you can hop back onto the main thread, then create a new snapshot using the actual product array, and apply this new snapshot to the collection view.

Does that help? I'm not sure I've answered the correct question here.

Here is my updated View Controller:

Here is my updated View Controller sorta or trying to do what you mentioned:

import UIKit



class ViewController: UIViewController {

    

    enum Section {

        case main

    }

    

    var collectionView: UICollectionView!

    var dataSource: UICollectionViewDiffableDataSource<Section,Product>?

    var products: [Product] = []

    

    

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view.

        

        navigationItem.title = "Products"

        view.backgroundColor = .white

        

        //Uncomment when needed

        configureHierarchy()

        configureDataSource()

        

        collectionView.register(ListCell.self, forCellWithReuseIdentifier: "ListCell")

        

    }

    

    func configure<T: SelfConfiguringCell>(with product: Product, for indexPath: IndexPath) -> T {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ListCell", for: indexPath) as? T else {

            fatalError("Unable to dequeue Cell")

        }

        cell.configure(with: product)

        return cell

    }

    

    func loadProducts() async {

        self.products = await APIService().listProducts()

    }

    

}



extension ViewController {

    private func createLayout() -> UICollectionViewLayout {

        let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)

        return UICollectionViewCompositionalLayout.list(using: config)

    }

}









extension ViewController {

    private func configureHierarchy() {

        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())

        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        view.addSubview(collectionView)

        collectionView.delegate = self

    }

    

    

    

    private func configureDataSource() {

        

        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Product> { (cell, indexPath, product) in

            var content = cell.defaultContentConfiguration()

            content.text = "\(product.name)"

            cell.contentConfiguration = content

        }

        

        dataSource = UICollectionViewDiffableDataSource<Section, Product>(collectionView: collectionView) {

            (collectionView: UICollectionView, indexPath: IndexPath, identifier: Product) -> UICollectionViewCell? in

            return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)

        }

        

        //inital data

       

        var snapshot = NSDiffableDataSourceSnapshot<Section, Product>()

        snapshot.appendSections([.main])

        //Problem loading this information

        snapshot.appendItems([], toSection: .main)

        dataSource?.apply(snapshot, animatingDifferences: false)

        

    }

    

}







extension ViewController: UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        collectionView.deselectItem(at: indexPath, animated: true)

    }

}
Where am I going wrong?
 
 
Q