Home > Net >  Collection view doesn't update
Collection view doesn't update

Time:06-29

I have 4 categories in segmented control. When i press on one of them collection view should show products in particular category. But instead of reusing cells and show only new items, collection view shows old items and in the end adds new cells with new items.

Where is proper place to use reloadData(). Or maybe i'm missing something?

Here is my code

private lazy var segmentedControl: UISegmentedControl = {
    var control = UISegmentedControl(items: ["All", "Men", "Women", "Jewelery", "Electro"])
    control.selectedSegmentTintColor = .black
    control.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
    control.tintColor = .white
   control.selectedSegmentIndex = 0
    control.addTarget(self, action: #selector(segmentChanged(_ :)), for: .valueChanged)
    return control
}()

override func viewDidLoad() {
    super.viewDidLoad()
  
    collectionView.delegate = self
    collectionView.dataSource = self
    
    networkManager.delegate = self
    
    setupMainStackView()
    setupCollectionView()
    networkManager.loadProducts(category: .all)
    performSearch() 
}

func performSearch() {
    if let category = NetworkManager.Category(rawValue: segmentedControl.selectedSegmentIndex) {
        networkManager.loadProducts(category: category)
    
        collectionView.reloadData()
    }
   // collectionView.reloadData()
}
@objc func segmentChanged(_ sender: UISegmentedControl) {
    performSearch()
}

// MARK: - Data Source extension MainViewController: UICollectionViewDataSource {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return productResults.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MainViewCollectionViewCell.identifier, for: indexPath) as! MainViewCollectionViewCell
  let listOfProduct = productResults[indexPath.row]
    cell.configure(for: listOfProduct)

        return cell
}

}

And here is how i search category

enum Category: Int {
     case all = 0
     case menSClothing = 1
     case womenSClothing = 2
     case electronics = 3
     case jewelery = 4
    
    var type: String {
        switch self {
        case .all: return ""
        case .menSClothing: return "category/men's clothing"
        case .womenSClothing: return "category/women's clothing"
        case .electronics: return "category/electronics"
        case .jewelery: return "category/jewelery"
        }
    }
}
private func fakeStoreURL(category: Category) -> URL {
    let kind = category.type
    let url = URL(string: "https://fakestoreapi.com/products/"   "\(kind)")
    return url!
}

func loadProducts(category: Category) {

    let url = fakeStoreURL(category: category)
    
    URLSession.shared.dataTask(with: url) {  data, response, error in
    if let error = error {
        print(error)
        return
    }
    guard let data = data else { return }
    do {
        var products = try JSONDecoder().decode([Product].self, from: data)
        products = self.parse(data: data)
        print(products)
        DispatchQueue.main.async {
            self.delegate?.didSendProductData(self, with: products)
        }
       
    } catch {
        print(error)
    }
}.resume()

}

CodePudding user response:

Problem is here

networkManager.loadProducts(category: category) 
collectionView.reloadData()

loadProducts is an asynchronous method , and reload of the collection occurs before the network data returns , so you need a completion

func loadProducts(category: Category,completion:@escaping([Product]? -> ())) {
    
    let url = fakeStoreURL(category: category)
    
    URLSession.shared.dataTask(with: url) {  data, response, error in
    if let error = error {
        print(error)
        completion(nil)
        return
    }
    guard let data = data else { return }
    do {
        var products = try JSONDecoder().decode([Product].self, from: data)
        products = self.parse(data: data)
        print(products)
        DispatchQueue.main.async {
          completion(products)
        }
       
    } catch {
        print(error)
        completion(nil)
    }
}.resume()

}

Then

networkManager.loadProducts(category: category) { [weak self] products in
   guard let products = products else { return }
   self?.productResults = products
   self?.collectionView.reloadData()
 } 
  • Related