Problème de reload tableView

#1

Hello à tous,

J’ai un petit soucis qui me fait tourner en rond sur un crash de mon app quand je recharge une TableView avec un message d’erreur qui me dit Fatal error: Index out of range. J’ai bien essayé de comprendre par moi même avec des print() à des moments clés, mais je ne trouve pas, du coup, je sollicite votre aide :slightly_smiling_face:

Cela vient TRÈÈÈÈÈÈÈÈÈÈS probablement du moment où j’appelle tableView.reloadData() :man_shrugging:t2:

//
//  SongHistoryViewController.swift
//  x3
//
//  Created by Didier Mauras on 27/08/2018.
//  Copyright © 2018 xxxxxxxxxxxxxxxxx. All rights reserved.
//

import UIKit

class SongHistoryViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var _songHistory:[Track] = []
    let refreshControl = UIRefreshControl()
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        refreshControl.addTarget(self, action: #selector(refresh(_:)), for: .valueChanged)
        if #available(iOS 10.0, *) {
            tableView.refreshControl = refreshControl
            tableView.refreshControl?.tintColor = #colorLiteral(red: 0.9335525036, green: 0.667769134, blue: 0, alpha: 1)
        } else {
            tableView.backgroundView = refreshControl
        }
    }
    override func viewWillAppear(_ animated: Bool) {
        updateHistory()
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if _songHistory.count == 0 {
            tableView.setEmptyView(smiley: "🤷🏻‍♂️" ,title: "La playlist est vide...", message: "Une émission est en cours?")
        }
        else {
            tableView.restoreTV()
        }
        return _songHistory.count
    }
    
    @IBAction func gestureViewTouched(_ sender: Any) {
        closeWindow()
    }
    
    @objc func refresh(_ refreshControl: UIRefreshControl) {
        // Do your job, when done:
        updateHistory()
        refreshControl.endRefreshing()
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "songHistory-cell", for: indexPath) as! SongHistoryTableViewCell
        print("reloading data", indexPath.row)
        let songHistory:Track = _songHistory[indexPath.row]
        cell.ui_titleLabel.text = songHistory.title
        cell.ui_artistLabel.text = songHistory.artist
        if let coverUrl = songHistory.cover300,
            coverUrl != "https://xxxxxxxxxxxxxxxxx.fr/cover/300_0-0.jpg",
            coverUrl != "https://xxxxxxxxxxxxxxxxx.fr/cover/200_0-0.jpg",
            let jacketURL = URL(string: coverUrl) {
            cell.ui_jackImage.af_setImage(withURL: jacketURL, placeholderImage: #imageLiteral(resourceName: "xxxxxxxxxxxxxxxxx"))
        } else {
            cell.ui_jackImage.image = #imageLiteral(resourceName: "xxxxxxxxxxxxxxxxx")
        }
        let formatter = DateFormatter()
        formatter.dateFormat = "HH:mm:ss"
        let laDate = formatter.string(from: songHistory.date!)
        cell.ui_dateLabel.text = String.localizedStringWithFormat(NSLocalizedString("played at %@", comment: "specifies when a song has been played"), laDate)
        return cell
    }
    
    @objc func updateHistory(_ sid:Int = 1) {
        
        let onair = Player.shared.getName()
        var stationId:Int
        
        switch onair {
        case "xxxxxxxxxxxxxxxxx":
            stationId = 1
        case "xxxxxxxxxxxxxxxxx":
            stationId = 2
        case "xxxxxxxxxxxxxxxxx":
            stationId = 3
        case "xxxxxxxxxxxxxxxxx":
            stationId = 4
        default:
            stationId = 1
        }
        
        print("refreshing", onair)
    
        self._songHistory.removeAll()
        let jsonUrl = "https://xxxxxxxxxxxxxxxxx.com/xxxxxxxxxxxxxxxxx/getplaylist?xxxxxxxxxxxxxxxxx=\(stationId)"
        guard let url = URL(string: jsonUrl) else { return }
        
        URLSession.shared.dataTask(with: url) { (data, response, err) in
            guard let data = data else { return }

            do {
                let radio =  try JSONDecoder().decode(Station.self, from: data)
                guard let tracks = radio.tracks else { return }
                for tracks in tracks {
                    self._songHistory.append(tracks)
                }
            DispatchQueue.main.async {
                print("reload data")
                self.tableView.reloadData()
            }
                print("_songHistory is filled")
            } catch let jsonErr {
                print("JSON error : ", jsonErr)
            }
        }.resume()
    }
    
    func closeWindow() {
        dismiss(animated: true, completion: nil)
    }
    
}

Merci à vous si vous trouvez, parce que moi, je sèche :kissing_closed_eyes:

Didier

1 Like
#2

Up please :slightly_smiling_face:

Voici le résultat de mes prints :

reload data

reloading data 0

reloading data 1

reloading data 2

reloading data 3

reloading data 4

reloading data 5

reloading data 6

reloading data 7

reloading data 8

reloading data 9

reloading data 10

reloading data 11

reloading data 12

reloading data 13

reloading data 14

reloading data 15

reloading data 16

reloading data 4

reloading data 5

Je ne sais pas pourquoi il y a 4 et 5 à la fin. Si quelqu’un pouvait éclairer ma lanterne, j’en serais fort reconnaissant :blush:

Les erreurs dans la console :

refreshing xxxxxxxxxxx

reloading data 4

Fatal error: Index out of range

2019-05-29 23:04:30.834772+0200 xx![40|690x13][2331:504247] Fatal error: Index out of range

Merci infiniment :pray:t2:

#3

@mbritto @draken désolé de vous identifier, mais je n’obtiens pas de réponse. Je ne sais pas pourquoi, peut être que j’ai omis quelque chose ou été impoli sans m’en rendre compte? Mais j’ai besoin d’aide snif

#4

Hello Didier,

Est-ce que tu peux faire un package de ton app pour que je puisse l’exécuter de mon côté et regarder ? Car là, c’est compliqué avec le code que tu donnes.

#5

Bonjour Didier,

il y a plusieurs choses que je ne comprends pas dans ton code, notamment des fonctions que tu appelles dans ta tableView mais qui normalement n’existent pas. Tu as ajouté des extensions ?

Sinon, je vois une erreur possible : dans ta fonction updateHistory() tu supprimes tout ta table, puis tu lances le chargement.

Le problème est qu’entre le moment où tu as supprimé tes lignes et le moment où le chargement se termine, le moindre appel à la fonction cellForRowAt va provoquer un crash.

Part du principes que tu ne dois jamais modifier le contenu de la variable _songHistory tant que tu n’as pas prévenu la table avec un reloadData() ou une fonction plus précise pour lui dire ce que tu as modifié ou supprimé.