Ajouter des Section dans un UITableView

Merci :blush:

Mais le fait est que je ne voie pas comment modifier le décryptage du JSON en plusieurs secteur.

Je désespère de mettre cette fonction de secteur dans mon appli mais je continue à chercher.

Eh bien, ne le fait pas … Ne touche surtout pas au décryptage du JSON !

En regardant ton code, je vois que tu as toutes les informations stockées sous forme d’objets WeatherProData, dans le tableau datas.

Il suffit de parcourir ce tableau pour trier les informations au format voulu. J’ai déjà expliqué comme traiter un problème similaire, quelque part sur le forum, à propos d’une application sportive, mais je ne sais plus où.

L’idée c’est de lire une première fois tous les éléments du tableau datas pour noter le nombre de dates différentes. Et de créer autant de tableaux qu’il y a de jours. Puis parcourir à nouveau le tableau datas pour copier chaque objet WeatherProData dans le tableau correspondant à son jour.

Ensuite c’est facile de gérer les sections, chaque tableau correspondant à sa propre section.

C’est presque la même logique que ton application, avec une étape supplémentaire de formatage des données, APRES la lecture des données brutes du JSON.

Par ici je crois : Calculs dans un Array et TableView

Non, gaveline. C’est un autre post, plus ancien, en réponse à une autre problématique de jean-charles, sur la même application sportive. Enfin je crois, je répond a tellement de personnes sur différents forums que je me mélange parfois les pédales. Je chercherais à tête reposée.

Merci à vous

@Draken je cherche dans tes messages mais comme tu es très actif c’est pas évident à trouver :wink:

J’essaie de faire avancer le schmilblik mais comme je suis novice …

En fait c’est ce topic là : TableView Sections avec des dates?

Merci à tous.

Après plusieurs essais, j’arrive à appliquer ce que j’ai lu sur un nouveau projet, mais je n’arrive pas à l’appliquer dans mon projet existant avec le JSON

Dans mon projet actuel les sections son reprise 15x avec a chaque fois toutes les cell en dessous

Hello @JefNewTech

Fais-nous voir ton code (le nouveau et celui sur le projet existant), qu’on y jette un oeil :slight_smile:

Bonne soirée,

Alexandre

Voici mon code qui ne fonctionne pas comme je veux. :scream:

import UIKit
import Alamofire
import MapKit

class WeatherProController: UIViewController, CLLocationManagerDelegate, UITableViewDataSource,UITableViewDelegate  {
    
    private let refreshControl = UIRefreshControl()
    
    var datas = [WeatherProData]()
    var locManager = CLLocationManager()
    var currentLocation: CLLocation!
    
    var timer = Timer()
    var jour = UIColor(red: 0, green: 191 / 255, blue: 1, alpha: 1)
    var nuit = UIColor(red: 51 / 255, green: 116 / 255, blue: 255 / 255, alpha: 1)
    
    let didBecomeActiveNotificationName = UIApplication.didBecomeActiveNotification
    
    let identifiantCell = "dataProCell"
    let identifiantSegue = "versDetailDonneePro"
    
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var menuButton: UIBarButtonItem!
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        locManager.requestAlwaysAuthorization()
        NotificationCenter.default.addObserver(self, selector: #selector(scheduleTimer), name: didBecomeActiveNotificationName, object: nil)
        changeBackground()
        data()
        
        // Add Refresh Control to Table View
        if #available(iOS 10.0, *) {
            tableView.refreshControl = refreshControl
        } else {
            tableView.addSubview(refreshControl)
        }
        // Configure Refresh Control
        refreshControl.addTarget(self, action: #selector(refreshWeatherData(_:)), for: .valueChanged)
        refreshControl.tintColor = UIColor.white
        let attributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
        refreshControl.attributedTitle = NSAttributedString(string: "Refreshing please wait", attributes: attributes)

    }
    
    @objc private func refreshWeatherData(_ sender: Any) {
        fetchWeatherData()
    }
    
    private func setupActivityIndicatorView() {
        activityIndicatorView.startAnimating()
    }
    
    private func fetchWeatherData() {
        data()
        self.refreshControl.endRefreshing()
//        self.activityIndicatorView.stopAnimating()
    }
    
    @objc func scheduleTimer() {
        // schedule the timer
        timer = Timer(fireAt: Calendar.current.nextDate(after: Date(), matching: DateComponents(hour: 6..<21 ~= Date().hour ? 21 : 6), matchingPolicy: .nextTime)!, interval: 0, target: self, selector: #selector(changeBackground), userInfo: nil, repeats: false)
        print(timer.fireDate)
        //        RunLoop.main.add(timer, forMode: .RunLoop.Mode.common)
        print("new background chenge scheduled at:", timer.fireDate.description(with: .current))
    }
    
    @objc func changeBackground(){
        // check if day or night shift
        self.view.backgroundColor =  6..<21 ~= Date().hour ? jour : nuit
        // schedule the timer
        scheduleTimer()
    }

    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return datas.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: identifiantCell) as? WeatherProCell {
            let data = datas[indexPath.row]
            cell.creerCell(data)
            return cell
        }
        return UITableViewCell()
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) as? WeatherProCell {
            cell.textIsHidden.isHidden = !cell.textIsHidden.isHidden
            cell.textIsHidden1.isHidden = !cell.textIsHidden1.isHidden
            cell.textIsHidden2.isHidden = !cell.textIsHidden2.isHidden
            cell.textIsHidden3.isHidden = !cell.textIsHidden3.isHidden
            cell.textIsHidden4.isHidden = !cell.textIsHidden4.isHidden
            cell.textIsHidden5.isHidden = !cell.textIsHidden5.isHidden
            cell.textIsHidden6.isHidden = !cell.textIsHidden6.isHidden
            cell.textIsHidden7.isHidden = !cell.textIsHidden7.isHidden
            cell.textIsHidden8.isHidden = !cell.textIsHidden8.isHidden
            cell.textIsHidden9.isHidden = !cell.textIsHidden9.isHidden
            cell.cloud.isHidden = !cell.cloud.isHidden
            cell.rTemp.isHidden = !cell.rTemp.isHidden
            cell.cloudBase.isHidden = !cell.cloudBase.isHidden
            cell.dewp.isHidden = !cell.dewp.isHidden
            cell.press.isHidden = !cell.press.isHidden
            cell.pressIcon.isHidden = !cell.pressIcon.isHidden
            cell.hydro.isHidden = !cell.hydro.isHidden
            cell.hydroIcon.isHidden = !cell.hydroIcon.isHidden
            cell.vent.isHidden = !cell.vent.isHidden
            cell.ventIcon.isHidden = !cell.ventIcon.isHidden
            cell.rainIcon.isHidden = !cell.rainIcon.isHidden
            cell.rain.isHidden = !cell.rain.isHidden
            cell.iso0.isHidden = !cell.iso0.isHidden
            cell.freezeRain.isHidden = !cell.freezeRain.isHidden
            cell.noSnow.isHidden = !cell.noSnow.isHidden
            cell.snowUp.isHidden = !cell.snowUp.isHidden
            cell.visibility.isHidden = !cell.visibility.isHidden
            cell.snowProb.isHidden = !cell.snowProb.isHidden
            
            tableView.beginUpdates()
            tableView.endUpdates()
            tableView.deselectRow(at: indexPath, animated: true)
        }
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return datas.count
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return datas[section].date
    }
    
    func data() {
        if ( CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
            CLLocationManager.authorizationStatus() == .authorizedAlways) {
            currentLocation = locManager.location
        }
        
        var headers: HTTPHeaders = [
            "Content-Type": "application/json"
        ]
        
        let user = loginWeatherPro
        let password = motDePasseWeatherPro
        
        if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
            headers[authorizationHeader.key] = authorizationHeader.value
        }
        
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.timeZone = TimeZone.init(abbreviation: "UTC")
        formatter.locale = Locale(identifier: "en_US_POSIX")
        print(formatter.string(from: now))
        let days = Calendar.current.date(byAdding: .day, value: 15, to: now)
        
        let urlB = urlDeBaseWeatherPro
        let locate = "locatedAt=\(currentLocation.coordinate.longitude),\(currentLocation.coordinate.latitude)"
        let period = "&validPeriod=PT0S"
        let validFrom = "&validFrom=\(formatter.string(from: now))"
        let validUntil = "&validUntil=\(formatter.string(from: days!))"
        let fields = "&fields=" + fieldsParameter
        let url = urlB + locate + period + validFrom + validUntil + fields
        print(url)
        
        Alamofire.request(url, headers:headers).responseJSON{ response in
            if let JSON = response.result.value as? [String: AnyObject] {
                if let forecast = JSON ["forecasts"] as? NSArray {
                    for element in forecast {
                        if let dict = element as? [String: AnyObject],
                            let dates = dict ["validFrom"] as? String ,
                            let weatherCode = dict ["weatherCode"] as? Int ,
                            let weatherCodeString = weatherCodesTab[weatherCode],
                            let temp = dict ["airTemperatureInCelsius"] as? Double ,
                            let cloud = dict ["effectiveCloudCoverInPercent"] as? Double ,
                            let rtemp = dict ["feelsLikeTemperatureInCelsius"] as? Double ,
                            let cloudBase = dict ["cloudBaseHeightInMeter"] as? Double ,
                            let dewp = dict ["dewPointTemperatureInCelsius"] as? Double ,
                            let press = dict ["airPressureAtSeaLevelInHectoPascal"] as? Double ,
                            let hydro = dict ["relativeHumidityInPercent"] as? Double ,
                            let vent = dict ["windSpeedInKilometerPerHour"] as? Double ,
                            let rain = dict ["precipitationProbabilityInPercent"] as? Double ,
                            let iso0 = dict ["freezingLevelHeightInMeter"] as? Double ,
                            let freezeRain = dict ["freezingRainProbabilityInPercent"] as? Double ,
                            let noSnow = dict ["noSnowPossibleBelowHeightInMeter"] as? Double ,
                            let snowUp = dict ["snowCertainAboveHeightInMeter"] as? Double ,
                            let visibility = dict ["visibilityInMeter"] as? Double ,
                            let snowProd = dict ["snowfallProbabilityInPercent"] as? Double {
                            
                            
                            self.datas.append(WeatherProData(date: (DateHelper.obtenir.jourDeLaSemaineWeather(dates)!) + " " + DateHelper.obtenir.dateWeatherPro(dates)! + " à " + (DateHelper.obtenir.heures(dates)!), weatherCode: weatherCodeString, temp: temp, cloud: cloud, rtemp: rtemp, cloudBase: cloudBase, dewp: dewp, press: press, hydro: hydro, vent: vent, rain: rain, iso0: iso0, freezeRain: freezeRain, noSnow: noSnow, snowUp: snowUp, visibility: visibility, snowProb: snowProd))
                            
//                            print(weatherCodeString)
                            
                            self.tableView.reloadData()
                        }
                    }
                }
            }
        }
    }
}

En effet, c’est tout à fait normal que cela ne fonctionne pas comme tu veux :

func numberOfSections(in tableView: UITableView) -> Int {
    return datas.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return datas.count
}

Tu définis le nombre de section de la même manière que tu définis les données dans les sections, cela ne me semble pas logique.

Quand je regarde la structure des objets dans le tableau “datas”, je vois ceci :

(DateHelper.obtenir.jourDeLaSemaineWeather(dates)!) + " " + DateHelper.obtenir.dateWeatherPro(dates)! + " à " + (DateHelper.obtenir.heures(dates)!)`

Je suppose que tout cela retourne une date (par exemple: lundi 12 décembre 13:05:56), peu importe le format.
Si tu veux ensuite grouper tes datas en fonction de leurs dates, tu vas devoir faire un tri.
Dans un premier temps, tu récupères tes données depuis Alamofire, aucun soucis. Ensuite, si j’étais toi, je parcourrai toutes les données que tu as récupérées via ta requêtes, et je les grouperais dans des tableaux distincts, en fonction de leurs dates.

Voici un exemple (je simplifie la structure pour une question de lisibilité) :

Imaginons que tes données de météo ne comporte qu’une date et un temps (nuageux, soleil, etc) et que tu as un tableau avec des données de ce type (ce que tu as récupéré avec Alamofire), voici comment tu pourrais faire pour classer toutes ces données par date :

for data in datas {

    // Si déjà au moins un élément dans le tableau des données groupées
    if datasGroupees.count > 0 {
        // Parcourt des éléments déjà présents dans le tableau des données groupées
        for (index, dataGroupee) in datasGroupees.enumerated() {
            
            // Par défaut, aucune section dans laquelle on doit ajouter l'élément, donc index -1
            var indexSection:Int = -1
            
            // Si le premier élément du sous tableau a la même date que l'élément que l'on souhaite ajouter, alors, la section existe déjà, on doit ajouter la données à cette section
            if dataGroupee[0].date == data.date {
                // Donc, on retient son index
                indexSection = index
                break
            }
            
            // Si aucune section avec la date du nouvel élement
            if indexSection == -1 {
                // Ajout de la nouvelle donnée comme si c'était un premier élément
                datasGroupees.append([data])
            }
            // Sinon, une section avec la même date existe déjà
            else {
                // Ajout de la donnée dans la section que l'on a trouvé tout à l'heure
                datasGroupees[indexSection].append(data)
            }
        }
        
    }
    // Sinon, premier élément
    else {
        datasGroupees.append([data])
    }

}

Ensuite, tu pourrais connaitre le nombre de sections en faisant :

datasGroupees.count

Et le nombre d’éléments dans une section en faisant :

datasGroupees[indexDeLaSectionVoulue].count
// indexDeLaSectionVoulue étant un numéro de section

Je me suis posé la même question il y a quelques temps (voir le lien du post de Draken), donc si je peux aider maintenant que j’ai compris une manière de faire, hésite pas ! :slight_smile:

Bonne soirée,

Alexandre

1 « J'aime »

Merci je vais essayer d’appliquer ce que tu me propose.

Bonjour et meilleur vœux à tous, je reviens vers vous car je n’ arrive pas à mettre en pratique vos exemple dans mon fichier.

Je vous demande donc encore un peut d’aide.

Merci

Hello @JefNewTech,

Peux-tu nous montrer le code que tu as essayé de faire ?
Ainsi, nous pourrons regarder et rectifier ensemble ce que tu as essayé de faire et ce qui ne va pas.

Bonne journée,

Alexandre

J’ai mis en suspend le projet original pour essayer d’y arriver sur un autre projet test mais rien n’y fait
J’ai fait quelque chose de rapide

import UIKit
import Alamofire

struct WeatherProData {
    
    let date: String // must be `Date` for smart grouping
//    let weatherCode: String
//    let temp: Double
//    let cloud: Doublea
//    let rTemp: Double
//    let cloudBase: Double
//    let dewp: Double
//    let press: Double
//    let hydro: Double
//    let vent: Double
//    let rain: Double
//    let iso0: Double
//    let freezeRain: Double
//    let noSnow: Double
//    let snowUp: Double
//    let visibility: Double
//    let snowProb: Double
}

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet weak var tableView: UITableView!
    
    var data = [WeatherProData]()
    var sections = [Date]()
    var dataT = [Date:[String]]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        
        let date = Date()
        let value = "Test"
        
        if !sections.contains(date) {
            sections.append(date)
            dataT[date] = [String]()
        }
        
        dataT[date]?.append(value)
        
        var headers : HTTPHeaders = ["Content-Type":"application.json"]
        
        //        Ajout lofin et mot de passe pour la connection à weather pro
        let user = loginWeatherPro
        let password = motDePasseWeatherPro
        
        //        Ajout de l'autorisation de connection
        if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
            headers[authorizationHeader.key] = authorizationHeader.value
        }
        
        //        formattage de l'heure
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.timeZone = TimeZone.init(abbreviation: "UTC")
        formatter.locale = Locale(identifier: "en_US_POSIX")
        print(formatter.string(from: now))
        let days = Calendar.current.date(byAdding: .day, value: 1, to: now)
        
        //        preparation de l'url de base
        let urlB = urlDeBaseWeatherPro
        let locate = "locatedAt=3.284752,50.644164"
        let period = "&validPeriod=PT0S"
        let validFrom = "&validFrom=\(formatter.string(from: now))"
        let validUntil = "&validUntil=\(formatter.string(from: days!))"
        let fields = "&fields=" + fieldsParameter
        let url = urlB + locate + period + validFrom + validUntil + fields
        
        Alamofire.request(url, headers:headers).responseJSON { response in
            if let JSON = response.result.value as? [String: AnyObject] {
                if let forecast = JSON ["forecasts"] as? NSArray {
                    for element in forecast {
                        if let dict = element as? [String: AnyObject],
                            let dates = dict ["validFrom"] as? String {
                            self.data.append(WeatherProData(date: dates))
                            print(dates)
                            self.tableView.reloadData()
                        }
                    }
                }
            }
        }
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return dataT.count
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "test"
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let datas = data[indexPath.row]
        cell.textLabel?.text = datas.date
        return cell
    }
}

J’essaye toujours. J’arrive à créer mes section mais pas à les afficher sans les heures.

J’aimerai que chaque section à comme titre le jours, et en dessous les heures de chaque jours.

import UIKit
import Alamofire

struct WeatherProData {
    
    let date: String // must be `Date` for smart grouping
//    let weatherCode: String
//    let temp: Double
//    let cloud: Doublea
//    let rTemp: Double
//    let cloudBase: Double
//    let dewp: Double
//    let press: Double
//    let hydro: Double
//    let vent: Double
//    let rain: Double
//    let iso0: Double
//    let freezeRain: Double
//    let noSnow: Double
//    let snowUp: Double
//    let visibility: Double
//    let snowProb: Double
}

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet weak var tableView: UITableView!
    
    @objc func refresh(_ sender: Any) {
        // Call webservice here after reload tableview.
        tableView.reloadData()
        refreshControl.endRefreshing()
    }
    
    var data = [WeatherProData]()
    var sections = [String]()
    var dateSection = [[WeatherProData]]()
    var refreshControl = UIRefreshControl()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        
//        RefrechControl sur UITableVIew
        refreshControl.attributedTitle = NSAttributedString(string: "Tirez pour rafraichir")
        refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
        self.tableView.addSubview(refreshControl)
        
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        
        
        var headers : HTTPHeaders = ["Content-Type":"application.json"]
        
        //        Ajout lofin et mot de passe pour la connection à weather pro
        let user = loginWeatherPro
        let password = motDePasseWeatherPro
        
        //        Ajout de l'autorisation de connection
        if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
            headers[authorizationHeader.key] = authorizationHeader.value
        }
        
        //        formattage de l'heure
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.timeZone = TimeZone.init(abbreviation: "UTC")
        formatter.locale = Locale(identifier: "en_US_POSIX")
        print(formatter.string(from: now))
        let days = Calendar.current.date(byAdding: .day, value: 1, to: now)
        
        let french = DateFormatter()
        french.dateStyle = .full
        french.dateFormat = "dd MMMM"
        french.locale = Locale(identifier: "FR_fr")
        print(french.string(from: now))
        
        //        preparation de l'url de base
        let urlB = urlDeBaseWeatherPro
        let locate = "locatedAt=3.284752,50.644164"
        let period = "&validPeriod=PT0S"
        let validFrom = "&validFrom=\(formatter.string(from: now))"
        let validUntil = "&validUntil=\(formatter.string(from: days!))"
        let fields = "&fields=" + fieldsParameter
        let url = urlB + locate + period + validFrom + validUntil + fields
        
        Alamofire.request(url, headers:headers).responseJSON { response in
            if let JSON = response.result.value as? [String: Any] {
                if let forecast = JSON ["forecasts"] as? NSArray {
                    for element in forecast {
                        if let dict = element as? [String: Any],
                            let dates = dict ["validFrom"] as? String {
                            self.data.append(WeatherProData(date: dates))
                            self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
                                WeatherProData.date
                            })))
                            self.sections.forEach({ (string) in self.dateSection.append([])})
                            for index in 0..<self.sections.count {
                                self.data.forEach({ (data) in
                                    if data.date == self.sections[index] {
                                        self.dateSection[index].append(data)
                                    }
                                })
                            }
                            self.tableView.reloadData()
                        }
                    }
                }
            }
        }
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sections[section]
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        for index in 0..<sections.count {
            if index == section {
                return dateSection[index].count
            }
        }
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
//        let datas = data[indexPath.row]
        cell.textLabel?.text = dateSection[indexPath.section] [indexPath.row].date
//        cell.textLabel?.text = datas.date
        self.tableView.addSubview(self.refreshControl)
        return cell
        
    }
}

Voici ce que j’obtiens.

Hello,

En fait tu enregistres dans ton tableau de sessions la donnée retournée par le webservice “WeatherProData.date”
Cette donnée est au format “Date” complet et il faut que tu la formate pour garder uniquement les informations que tu veux.

Essai ça:

let dateFormatterPrint = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"

self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
       dateFormatter.string(from: fullDate) // output 14/01/2019
})))

Merci, mais ces sections vont me rendre fous.

Pas moyen d’afficher la section avec la date du jour et afficher en dessous les infos par heure

import UIKit
import Alamofire

struct WeatherProData {
    
    let date: String // must be `Date` for smart grouping
//    let weatherCode: String
//    let temp: Double
//    let cloud: Doublea
//    let rTemp: Double
//    let cloudBase: Double
//    let dewp: Double
//    let press: Double
//    let hydro: Double
//    let vent: Double
//    let rain: Double
//    let iso0: Double
//    let freezeRain: Double
//    let noSnow: Double
//    let snowUp: Double
//    let visibility: Double
//    let snowProb: Double
}

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet weak var tableView: UITableView!
    
    @objc func refresh(_ sender: Any) {
        // Call webservice here after reload tableview.
        tableView.reloadData()
        refreshControl.endRefreshing()
    }
    
    var data = [WeatherProData]()
    var sections = [String]()
    var dateSection = [[WeatherProData]]()
    var refreshControl = UIRefreshControl()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        
//        RefrechControl sur UITableVIew
        refreshControl.attributedTitle = NSAttributedString(string: "Tirez pour rafraichir")
        refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
        self.tableView.addSubview(refreshControl)
        
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        
        
        var headers : HTTPHeaders = ["Content-Type":"application.json"]
        
        //        Ajout lofin et mot de passe pour la connection à weather pro
        let user = loginWeatherPro
        let password = motDePasseWeatherPro
        
        //        Ajout de l'autorisation de connection
        if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
            headers[authorizationHeader.key] = authorizationHeader.value
        }
        
        //        formattage de l'heure
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.timeZone = TimeZone.init(abbreviation: "UTC")
        formatter.locale = Locale(identifier: "en_US_POSIX")
        print(formatter.string(from: now))
        let days = Calendar.current.date(byAdding: .day, value: 1, to: now)
        
        let french = DateFormatter()
        french.dateStyle = .full
        french.dateFormat = "dd MMMM"
        french.locale = Locale(identifier: "FR_fr")
        
        //        preparation de l'url de base
        let urlB = urlDeBaseWeatherPro
        let locate = "locatedAt=3.284752,50.644164"
        let period = "&validPeriod=PT0S"
        let validFrom = "&validFrom=\(formatter.string(from: now))"
        let validUntil = "&validUntil=\(formatter.string(from: days!))"
        let fields = "&fields=" + fieldsParameter
        let url = urlB + locate + period + validFrom + validUntil + fields
        
        Alamofire.request(url, headers:headers).responseJSON { response in
            if let JSON = response.result.value as? [String: Any] {
                if let forecast = JSON ["forecasts"] as? NSArray {
                    for element in forecast {
                        if let dict = element as? [String: Any],
                            let dates = dict ["validFrom"] as? String {
                            self.data.append(WeatherProData(date: dates))
                            self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
                                french.string(from: ???)
                            })))
                            self.sections.forEach({ (string) in self.dateSection.append([])})
                            for index in 0..<self.sections.count {
                                self.data.forEach({ (data) in
                                    if data.date == self.sections[index] {
                                        self.dateSection[index].append(data)
                                    }
                                })
                            }
                            self.tableView.reloadData()
                        }
                    }
                }
            }
        }
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sections[section]
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        for index in 0..<sections.count {
            if index == section {
                return dateSection[index].count
            }
        }
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
//        let datas = data[indexPath.row]
        cell.textLabel?.text = dateSection[indexPath.section] [indexPath.row].date
//        cell.textLabel?.text = datas.date
        self.tableView.addSubview(self.refreshControl)
        return cell
        
    }
}

Voici ce que le JSON donne comme info :

{
    "forecasts": [
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-21T21:00:00+01:00",
            "validUntil": "2019-01-21T21:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2.3,
            "dewPointTemperatureInCelsius": -4.3,
            "feelsLikeTemperatureInCelsius": -5.6,
            "airPressureAtSeaLevelInHectoPascal": 1019.4,
            "windSpeedInKilometerPerHour": 8.5,
            "windDirectionInDegree": 186,
            "effectiveCloudCoverInPercent": 11,
            "totalCloudCoverInOcta": 3.8,
            "cloudCoverLowerThan2000MeterInOcta": 0,
            "cloudCoverLowerThan5000MeterInOcta": 0,
            "cloudBaseHeightInMeter": -1,
            "relativeHumidityInPercent": 86,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 8.7,
            "snowfallProbabilityInPercent": 0,
            "visibilityInMeter": 8461,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 0,
            "precipitationProbabilityInPercent": 0,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 1,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-21T22:00:00+01:00",
            "validUntil": "2019-01-21T22:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2.5,
            "dewPointTemperatureInCelsius": -4.4,
            "feelsLikeTemperatureInCelsius": -6.4,
            "airPressureAtSeaLevelInHectoPascal": 1018.7,
            "windSpeedInKilometerPerHour": 10.4,
            "windDirectionInDegree": 182,
            "effectiveCloudCoverInPercent": 15,
            "totalCloudCoverInOcta": 4.5,
            "cloudCoverLowerThan2000MeterInOcta": 0,
            "cloudCoverLowerThan5000MeterInOcta": 0.3,
            "cloudBaseHeightInMeter": 1398,
            "relativeHumidityInPercent": 87,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 1,
            "visibilityInMeter": 9411,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 0,
            "precipitationProbabilityInPercent": 1,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 1,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-21T23:00:00+01:00",
            "validUntil": "2019-01-21T23:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2.5,
            "dewPointTemperatureInCelsius": -4.5,
            "feelsLikeTemperatureInCelsius": -6.7,
            "airPressureAtSeaLevelInHectoPascal": 1018,
            "windSpeedInKilometerPerHour": 11.7,
            "windDirectionInDegree": 180,
            "effectiveCloudCoverInPercent": 23,
            "totalCloudCoverInOcta": 5.1,
            "cloudCoverLowerThan2000MeterInOcta": 0,
            "cloudCoverLowerThan5000MeterInOcta": 0.6,
            "cloudBaseHeightInMeter": 2797,
            "relativeHumidityInPercent": 86,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 5,
            "visibilityInMeter": 10672,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 1,
            "precipitationProbabilityInPercent": 5,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 2,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T00:00:00+01:00",
            "validUntil": "2019-01-22T00:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2.5,
            "dewPointTemperatureInCelsius": -4.5,
            "feelsLikeTemperatureInCelsius": -7,
            "airPressureAtSeaLevelInHectoPascal": 1017,
            "windSpeedInKilometerPerHour": 12.8,
            "windDirectionInDegree": 179,
            "effectiveCloudCoverInPercent": 33,
            "totalCloudCoverInOcta": 5.5,
            "cloudCoverLowerThan2000MeterInOcta": 0,
            "cloudCoverLowerThan5000MeterInOcta": 1.1,
            "cloudBaseHeightInMeter": 6082,
            "relativeHumidityInPercent": 86,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 7,
            "visibilityInMeter": 11781,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 1,
            "precipitationProbabilityInPercent": 7,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 3,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T01:00:00+01:00",
            "validUntil": "2019-01-22T01:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2.5,
            "dewPointTemperatureInCelsius": -4.5,
            "feelsLikeTemperatureInCelsius": -7.2,
            "airPressureAtSeaLevelInHectoPascal": 1016,
            "windSpeedInKilometerPerHour": 13.7,
            "windDirectionInDegree": 179,
            "effectiveCloudCoverInPercent": 45,
            "totalCloudCoverInOcta": 5.9,
            "cloudCoverLowerThan2000MeterInOcta": 0,
            "cloudCoverLowerThan5000MeterInOcta": 2.1,
            "cloudBaseHeightInMeter": 6078,
            "relativeHumidityInPercent": 86,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 7,
            "visibilityInMeter": 12390,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 1,
            "precipitationProbabilityInPercent": 8,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 4,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T02:00:00+01:00",
            "validUntil": "2019-01-22T02:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2.4,
            "dewPointTemperatureInCelsius": -4.3,
            "feelsLikeTemperatureInCelsius": -7.4,
            "airPressureAtSeaLevelInHectoPascal": 1014.7,
            "windSpeedInKilometerPerHour": 15.2,
            "windDirectionInDegree": 179,
            "effectiveCloudCoverInPercent": 56,
            "totalCloudCoverInOcta": 6.3,
            "cloudCoverLowerThan2000MeterInOcta": 0,
            "cloudCoverLowerThan5000MeterInOcta": 3,
            "cloudBaseHeightInMeter": 6073,
            "relativeHumidityInPercent": 86,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 8,
            "visibilityInMeter": 12892,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 1,
            "precipitationProbabilityInPercent": 8,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 4,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T03:00:00+01:00",
            "validUntil": "2019-01-22T03:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2.1,
            "dewPointTemperatureInCelsius": -4.1,
            "feelsLikeTemperatureInCelsius": -7.3,
            "airPressureAtSeaLevelInHectoPascal": 1013.3,
            "windSpeedInKilometerPerHour": 16.7,
            "windDirectionInDegree": 178,
            "effectiveCloudCoverInPercent": 65,
            "totalCloudCoverInOcta": 6.6,
            "cloudCoverLowerThan2000MeterInOcta": 0,
            "cloudCoverLowerThan5000MeterInOcta": 3.7,
            "cloudBaseHeightInMeter": 4008,
            "relativeHumidityInPercent": 86,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 7,
            "visibilityInMeter": 13884,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 1,
            "precipitationProbabilityInPercent": 7,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 5,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T04:00:00+01:00",
            "validUntil": "2019-01-22T04:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -1.9,
            "dewPointTemperatureInCelsius": -3.9,
            "feelsLikeTemperatureInCelsius": -7.3,
            "airPressureAtSeaLevelInHectoPascal": 1011.8,
            "windSpeedInKilometerPerHour": 18.1,
            "windDirectionInDegree": 177,
            "effectiveCloudCoverInPercent": 74,
            "totalCloudCoverInOcta": 6.9,
            "cloudCoverLowerThan2000MeterInOcta": 0.3,
            "cloudCoverLowerThan5000MeterInOcta": 4.5,
            "cloudBaseHeightInMeter": 4008,
            "relativeHumidityInPercent": 86,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 6,
            "visibilityInMeter": 14956,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 1,
            "precipitationProbabilityInPercent": 6,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 6,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T05:00:00+01:00",
            "validUntil": "2019-01-22T05:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -2,
            "dewPointTemperatureInCelsius": -3.8,
            "feelsLikeTemperatureInCelsius": -7.8,
            "airPressureAtSeaLevelInHectoPascal": 1010.4,
            "windSpeedInKilometerPerHour": 20.4,
            "windDirectionInDegree": 177,
            "effectiveCloudCoverInPercent": 76,
            "totalCloudCoverInOcta": 7,
            "cloudCoverLowerThan2000MeterInOcta": 0.6,
            "cloudCoverLowerThan5000MeterInOcta": 4.6,
            "cloudBaseHeightInMeter": 5411,
            "relativeHumidityInPercent": 88,
            "freezingLevelHeightInMeter": 0,
            "freezingRainProbabilityInPercent": 0,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 9,
            "visibilityInMeter": 13442,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 2,
            "precipitationProbabilityInPercent": 10,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 6,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T06:00:00+01:00",
            "validUntil": "2019-01-22T06:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -1.8,
            "dewPointTemperatureInCelsius": -3.6,
            "feelsLikeTemperatureInCelsius": -7.7,
            "airPressureAtSeaLevelInHectoPascal": 1008.9,
            "windSpeedInKilometerPerHour": 21.3,
            "windDirectionInDegree": 176,
            "effectiveCloudCoverInPercent": 83,
            "totalCloudCoverInOcta": 7.1,
            "cloudCoverLowerThan2000MeterInOcta": 1.6,
            "cloudCoverLowerThan5000MeterInOcta": 5.4,
            "cloudBaseHeightInMeter": 1588,
            "relativeHumidityInPercent": 87,
            "freezingLevelHeightInMeter": 722,
            "freezingRainProbabilityInPercent": 1,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 13,
            "visibilityInMeter": 13463,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 4,
            "precipitationProbabilityInPercent": 15,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 7,
            "weatherCodeTraditional": 0
        },
        {
            "locatedAt": [
                3.284752,
                50.644165
            ],
            "stationTimeZoneName": "Europe/Brussels",
            "validFrom": "2019-01-22T07:00:00+01:00",
            "validUntil": "2019-01-22T07:00:00+01:00",
            "validPeriod": "PT0S",
            "airTemperatureInCelsius": -1.3,
            "dewPointTemperatureInCelsius": -3.2,
            "feelsLikeTemperatureInCelsius": -7.1,
            "airPressureAtSeaLevelInHectoPascal": 1007.7,
            "windSpeedInKilometerPerHour": 21.5,
            "windDirectionInDegree": 175,
            "effectiveCloudCoverInPercent": 95,
            "totalCloudCoverInOcta": 7.7,
            "cloudCoverLowerThan2000MeterInOcta": 5.2,
            "cloudCoverLowerThan5000MeterInOcta": 7.1,
            "cloudBaseHeightInMeter": 1457,
            "relativeHumidityInPercent": 87,
            "freezingLevelHeightInMeter": 749.1,
            "freezingRainProbabilityInPercent": 1,
            "noSnowPossibleBelowHeightInMeter": 0,
            "snowCertainAboveHeightInMeter": 0,
            "snowfallProbabilityInPercent": 19,
            "visibilityInMeter": 14784,
            "clearSkyUVIndex": 0,
            "uvIndexWithClouds": 0,
            "convectivePrecipitationProbabilityInPercent": 7,
            "precipitationProbabilityInPercent": 22,
            "precipitationType": 71,
            "hailProbabilityInPercent": 0,
            "thunderstormProbabilityInPercent": 0,
            "weatherCode": 8,
            "weatherCodeTraditional": 0
        }
    ]
}

Merci

Hello,

Qu’est-ce que tu obtiens comme display sur ton app ?

Hello,

Sur je met ceci :

 self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
                                french.string(from: ????)
                            })))

forcement je n’arrive pas à compiler car from : ??? je ne voie pas quoi mettre !

mais si je fait comme avant que s0ta m’explique j’ai ceci :

self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
                                WeatherProData.date
                            })))

Hello,

Il faut que tu mettes

self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
                            french.string(from: WeatherProData.date)
                        })))

J’imagine que WeatherProData.date te retourne un objet au format Date. Si ce n’est pas le cas, tu dois le convertir au format Date au moment de le recevoir dans ta closure.