Search code examples
uitableviewcollectionview

Swift - ReloadData not update


I'm trying to fill CollectionView in Swift with data from a Json Structure but I'm not able to reload the array and parse into the collectionView I'm declaring an Array(V_textoturismo) and I parse the content of JSON to it, but seems that is not able or when it passes I can't reload the collection view. If I made it with an static Array(texto) I can't do it without a problem Thanks 4 everything I Attach my code:

import UIKit

struct category: Codable {
           let textoturismo: String
           let imagenturismo: String
           let destinoturismo: String
}
struct Entry_category: Codable {
           let categories: [String: category]
}

class CollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
    
    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet var menuButton:UIBarButtonItem!
    
    var v_textoturismo:[String] = []
    var v_imagenturismo:[String] = []
    var v_destinoturismo:[String] = []
    
    let imagen = ["Perdidos", "Friends", "Breaking Bad", "Dexter"]
    let texto = [NSLocalizedString("Hotels", comment: ""),
                        NSLocalizedString("Restaurants", comment: ""),
                        NSLocalizedString("Bars&Pubs", comment: ""),
                        NSLocalizedString("Discoteques", comment: "")]

    override func viewDidLoad() {
        super.viewDidLoad()
        //collectionView?.dataSource = self;
        //collectionView?.delegate = self;
        
        if self.revealViewController() != nil {
            menuButton.target = self.revealViewController()
            menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
            self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
        }
        if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout{
            //layout.minimumLineSpacing = 10
            //layout.minimumInteritemSpacing = 10
            //layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 0)
            //let size = CGSize(width:(collectionView!.bounds.width)/2, height: 150)
            let size = CGSize(width:(collectionView!.frame.size.width)/2, height: 150)
            layout.itemSize = size
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return v_textoturismo.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let identifier = "Item"
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! SeriesCollectionViewCell
        //cell.itemLabel.text = texto[indexPath.row]
        cell.itemLabel.text = v_textoturismo[indexPath.row]
        cell.itemImage.image = UIImage.init(imageLiteralResourceName: imagen[indexPath.row])
        return cell
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let item = sender as? UICollectionViewCell
        let indexPath = collectionView.indexPath(for: item!)
        let detailVC = segue.destination as! DetailViewController
        detailVC.detailName = imagen[(indexPath?.row)!]
    }
    
    func parseCategories(){
        //Leo JSON categorias
               
               NSLog("entro")
               if let url2 = URL(string: "http://s369243288.mialojamiento.es/WS_CB_Addicts/categorias_turismo/json_data.php") {
                  URLSession.shared.dataTask(with: url2) { data, response, error in
                     if let data = data {
                     let jsonDecoder = JSONDecoder()
                     do {
                     let parsedJSON = try jsonDecoder.decode(Entry_category.self, from: data)
                     for category in parsedJSON.categories {
                       self.v_textoturismo.append(category.value.textoturismo)
                       print(category.value.textoturismo)
                       self.v_imagenturismo.append(category.value.imagenturismo)
                       self.v_destinoturismo.append(category.value.destinoturismo)
                       print(category.value.destinoturismo)
                     //print(image.value.destino)
                                 }
                             } catch {
                     print(error)
                             }
                            }
                        }.resume()
               }
               //End Leo JSON categorias
    }
    
    override func viewWillAppear(_ animated: Bool) {
          //super.viewWillAppear(animated)
          parseCategories()
          //self.collectionView.reloadData()
        DispatchQueue.main.async {
            self.collectionView.reloadData()
        }
        print(v_textoturismo)
      }
}

Solution

  • Your collection view datasource lines are commented out, so I assume you're setting this up in Interface Builder / Storyboards?

            //collectionView?.dataSource = self;
            //collectionView?.delegate = self;
    

    If these are not set your collection view will always be empty.

    Side note: semicolons not necessary here

    Next, looking at your viewWillAppear method, there are multiple issues here. Firstly, always always always call super unless the framework specifically tells you not to. There could be hidden behavior here in a future version of iOS that you might miss out on.

    In fact, the docs state:

    If you override this method, you must call super at some point in your implementation.

    Next, you might consider only calling parseCategories in viewDidLoad instead of viewWillAppear. You probably don't want this called every single time they arrive at this screen, if they switch tabs, for instance.

    Your DispatchQueue.main.async call is unnecessary here. This method is always called on the main queue.

    Calling reloadData here is not correct either, you want to do this when there is new data to be loaded, and right now you have just called parseCategories which issues a network request, so you have to wait for that to come back first.

    Inside your parseCategories method you are not handling the case where the network request comes back with an Error, or a non-successful HTTP status code.

    Finally, in the success block after parsing the data, you add the categories to an array, but you never tell the collection view to reload here. You need:

    DispatchQueue.main.async { 
        self.collectionView.reloadData()
    }
    

    after you've added the data to the v_textoturismo array.