Stocker des données (Array/JSON) ?

Bonjour à  tous,


 


je suis développeur débutant sous XCode/Swift3.


 


Je réalise un application simple pour iOS dans laquelle je souhaite collecter des données de la part de l'utilisateur au travers de plusieurs écrans, comme un wizard (Navigation controller ok).


 


La question que je me pose est : comment stocker les choix de l'utilisateur ?


J'aimerais partir sur un Array, mais je galère pour stock ceci :


 


Ecran 1 :


  • Choix A

Ecran 2 :


  • Choix B
  • --- Valeur 1

Ecran 3 :


  • Choix B
  • et Choix D
  • --- Valeur 1
  • --- Valeur "Toto"

 


En fonction des réponses, j'imaginais créer un tableau de tableau multi-type pouvant accueillir des String, des Int, des Dates, etc...


 


Enfin, je souhaitais sérialiser ce tableau dans une chaà®ne JSon pour l'envoyer vers un serveur avec une requête http (API REST).


 


Je suis parti sur une classe toute simple :




class appDataProfs: NSObject {

var data : [String : AnyObject]

// Constructeur
override init() {
self.data = ["":AnyObject.self as AnyObject]
super.init()
}


}

Ensuite, j'ai fais le gros dégelasse pour mes tests et je déclare ceci dans mon AppDelegate :



var globalAppDataProfs = appDataProfs() // On que c'est pas beau !!!! :(


Et je l'alimente dans une méthode de ViewController comme ça :



globalAppDataProfs.data["Eleve"] = "Margot" as AnyObject
globalAppDataProfs.data["Coucou"] = "Zoulou" as AnyObject
globalAppDataProfs.data["SousDonnées"] = ["sd1", "sd2"] as AnyObject


Bref, je lutte pas mal et vos conseils seront les bienvenus. Merci d'avance.


 


Mots clés:

Réponses

  • DrakenDraken Membre
    octobre 2017 modifié #2

    Swift 3 ? Met à  jour Xcode et passe à  Swift 4, dont l'un des avantages est de gérer le Json nativement.


     


    Un tuto sur la question : http://benscheirman.com/2017/06/ultimate-guide-to-json-parsing-with-swift-4/

  • CéroceCéroce Membre, Modérateur
    Il y a au moins deux approches possibles:
    - stocker en vrac dans un dictionnaire
    - stocker dans des objets.

    Généralement, on partira plutôt sur la seconde:


    class Class {
    var identifier: String?
    var pupils: [Pupil] = []
    }

    enum Gender: String {
    case male
    case female
    }

    class Pupil {
    var firstName: String?
    var lastName: String?
    var gender: Gender?
    }
    Et pour utiliser:

    let pupil = Pupil()
    pupil.firstName = "Renaud"
    pupil.lastName = "Pradenc"
    pupil.gender = .male
    Remarque que les champs sont identifiés par des propriétés, et on ne peut donc pas se tromper sur les clefs, contrairement à  un dictionnaire.
  • CéroceCéroce Membre, Modérateur
    Conversion en JSON

    Cette conversion se fait généralement à  l'aide de (NS)JSONSerialization, qui renvoie une (NS)Data en sérialisant des objets Foundation " c'est à  dire des dictionnaires et arrays.

    Il faut donc que chaque objet renvoie un dictionnaire. On peut donc écrire ceci:
     
    class Pupil {
    var firstName: String?
    var lastName: String?
    var gender: Gender?

    func dictionary() -> [String: Any] {
    var dic:[String: Any] = [:]
    if let firstName = firstName {
    dic["firstName"] = firstName
    }
    if let lastName = lastName {
    dic["lastName"] = lastName
    }
    if let gender = gender {
    dic["gender"] = gender.rawValue
    }
    return dic
    }
    }
    Et pour convertir en JSON:
     
    let dic = pupil.dictionary()
    let json = try? JSONSerialization.data(withJSONObject: dic, options: [])
  • CéroceCéroce Membre, Modérateur
    On peut remarquer que la conversion en dictionnaire est non-seulement ennuyeuse, mais peut amener des erreurs sur les noms des clefs. Or, comme le fait remarquer très justement Draken, Swift 4 propose un nouveau mécanisme pour générer les dictionnaires. ça me semble trop complexe pour un débutant, mais tu pourras jeter un oe“il à  l'article dans le futur.


  • Swift 3 ? Met à  jour Xcode et passe à  Swift 4, dont l'un des avantages est de gérer le Json nativement.


     


    Un tuto sur la question : http://benscheirman.com/2017/06/ultimate-guide-to-json-parsing-with-swift-4/




     


    Merci pour ta réponse.


    Je suis en dernière version d'XCode 9.0.1 donc Swift4 j'imagine. Je ne sais pas comment vérifier.

  • MachaonMachaon Membre
    octobre 2017 modifié #7


    On peut remarquer que la conversion en dictionnaire est non-seulement ennuyeuse, mais peut amener des erreurs sur les noms des clefs. Or, comme le fait remarquer très justement Draken, Swift 4 propose un nouveau mécanisme pour générer les dictionnaires. ça me semble trop complexe pour un débutant, mais tu pourras jeter un oe“il à  l'article dans le futur.




     


    Merci beaucoup pour tes réponses rapides et complète, je vais étudier cela de prés.


     


    Cependant, passer par un objet me paraà®t très complexe, surtout quand, au final, mon "arbre" de données doit être celui-ci :


     


    Pour 1 Elève [Alpha Prénom] et 1 date [Date] de prochain cours, j'ai à  stocker :


    ·      Programme n°1 : [Alpha ou IdProgramme]


    o   Evaluation (une seule)


    §  Une note de [1 à  3]


    §  Un Commentaire [Alpha 400]


    o   Objectif n°1 (est composé de) :


    §  Parties : [choix multiple parmi A à  Z] ou [mesure x]


    ·      Actions : [choix multiple parmi] :


    o   Mens.


    o   MSep.


    o   Par coe“ur


    o   X


    o   Y


    o   Z


    o   Etc...


    ·      Métronome :


    o   Tempo : [Int]


    o   Rythme de référence [Noire ou Croche]


    ·      Nombre de répétitions : [Int]


    Méthode de travail


    ·      Temps de travail [Int] en minutes


    ·      Points d'attentions : (est composé de)


    o   Texte [Choix multiple parmi] :


    §  Doigté


    §  Concentration


    §  Lecture


    §  Etc...


    o   Corps [Choix multiple parmi] :


    §  Epaules


    §  Dos


    §  Bras


    §  Doigts


    o   Interprétation :


    §  Commentaire [Alpha]


    §  Objectif n°2 (est composé de) :


    ·      ...


    ·      Programme n°2 : [Alpha ou IdProgramme]


    o   ...




  • On peut remarquer que la conversion en dictionnaire est non-seulement ennuyeuse, mais peut amener des erreurs sur les noms des clefs. Or, comme le fait remarquer très justement Draken, Swift 4 propose un nouveau mécanisme pour générer les dictionnaires. ça me semble trop complexe pour un débutant, mais tu pourras jeter un oe“il à  l'article dans le futur.




     


    Tu parles de ce genre de fonctions ?


    ça me paraà®t digeste...


     


    https://www.raywenderlich.com/172145/encoding-decoding-and-serialization-in-swift-4


     


    Merci

  • CéroceCéroce Membre, Modérateur
    Disons que dans un cas simple, il suffit que les classes se conforment à  Codable. ça peut juste devenir compliqué si par exemple, le JSON ne ressemble pas à  ta structure interne " ce qui dans la vraie vie est toujours le cas.
  • CéroceCéroce Membre, Modérateur
    octobre 2017 modifié #10

    Cependant, passer par un objet me paraà®t très complexe, surtout quand, au final, mon "arbre" de données doit être celui-ci :

    Je suis parti d'un cas classique, mais c'est vrai qu'on ne peut pas donner une solution sans connaà®tre vraiment le problème.
    Dans ton cas, il est probable que tu auras de toute façon un JSON en entrée pour définir le questionnaire, et tu réutiliseras les clefs pour stocker les résultats.

  • Je suis parti d'un cas classique, mais c'est vrai qu'on ne peut pas donner une solution sans connaà®tre vraiment le problème.

    Dans ton cas, il est probable que tu auras de toute façon un JSON en entrée pour définir le questionnaire, et tu réutiliseras les clefs pour stocker les résultats.




    Oui tu as tout à  fait raison.

    Je vais donc tout decrire en objets, propriétés simples et énumérations, maisn pour un gars qui vient du PHP sans fois ni loi ça fait bizarre 😂😂😂


    Merci encore pour votre aide.


  • Je suis en dernière version d'XCode 9.0.1 donc Swift4 j'imagine. Je ne sais pas comment vérifier.




    Oui, c'est bien du Swift 4.


    Swift 3 c'était Xcode 8.

  • CéroceCéroce Membre, Modérateur

    Je vais donc tout decrire en objets, propriétés simples et énumérations, maisn pour un gars qui vient du PHP sans fois ni loi ça fait bizarre

    Justement, à  voir ce réflexe de tout stocker en vrac dans un dictionnaire, j'ai spontanément supposé que tu étais un programmeur PHP ;-)

    Je ne vais pas relancer le débat sur le typage statique vs. le typage dynamique, mais tu verras qu'un compilateur qui prévient des erreurs lors de la frappe, c'est bien mieux que de lancer l'application, s'apercevoir qu'elle ne fonctionne pas, puis faire la chasse au bug.
  • LeChatNoirLeChatNoir Membre, Modérateur


    Justement, à  voir ce réflexe de tout stocker en vrac dans un dictionnaire, j'ai spontanément supposé que tu étais un programmeur PHP ;-)


    Je ne vais pas relancer le débat sur le typage statique vs. le typage dynamique, mais tu verras qu'un compilateur qui prévient des erreurs lors de la frappe, c'est bien mieux que de lancer l'application, s'apercevoir qu'elle ne fonctionne pas, puis faire la chasse au bug.




     


    Alors là  les mecs, je viens appuyer sur ce point.


    C'est un conseil que m'avait donné Ali à  l'époque sans trop insister et je ne l'avais pas écouté. Toute mon appli repose sur des tableaux de dictionnaires.


     


    Ca marche bien, pas de soucis mais en maintenance, c'est juste une horreur. Te remettre dans le code 2, 3, 4 ans après, c'est vraiment pas facile. En outre, je passe petit à  petit l'appli en swift et manipuler des NSDicionary, c'est chiant.


     


    Au final, j'ai fini par créer des objets et je suis en pleine session de modif de code pour utiliser les objets au lieu des dictionnaires et je constate qu'effectivement, tout est plus simple, tout est plus clair.


     


    Le compilo complète, swift est moins chiant, le code est plus clair, je peux manipuler directement dans CoreData. Bref, si c'est pas le bonheur, ça y ressemble :)


     


    Donc Machaon, ne te pose pas la question. Fais des objets :)


  • Ok Messieurs, merci pour vos conseils, j'ai tout fait en objet, de toutes façons avec des dictionnaires c'était l'enfer.


    Par contre, ça me fait une structure monstrueuse.


    Ensuite le passage en JSON, ça prend 3 lignes, c'est super.


    (comme en PHP en fait avec un ArrayToJson  8--) ).


     


    PS : Il me tarde de coder l'API côté serveur... en PHP  :D


    J'ai pas encore tous les reflexes avec ce full objet surtout avec des données riches comme ci-dessous :




    class DataProfesseur: Codable {
    var eleve : String // Pour l'instant dans la maquette, on gère 1 elève à  la fois, juste par son prénom
    var dateProchainCours : Date
    var programmes : [Programmes]

    init(eleve: String, dateProchainCours : Date) {
    self.eleve = eleve
    self.dateProchainCours = dateProchainCours
    self.programmes = []
    }
    }

    class Programmes : Codable {
    var nomProgramme : String
    var evaluation : Evaluation
    var finalités : [Finalité]
    var pointsDAttention : [PointsDAttention]

    init() {
    self.nomProgramme = ""
    self.evaluation = Evaluation()
    self.finalités = [Finalité()]
    self.pointsDAttention = [PointsDAttention()]
    }
    }

    class Evaluation : Codable {
    var note : Int // de 1 à  3
    var commentaire : String

    init() {
    self.note = 0
    self.commentaire = ""
    }
    }

    class Finalité : Codable {
    var parties : [Parties]

    init() {
    self.parties = [Parties()]
    }
    }

    class Parties : Codable {
    var parties : [enumParties]
    var metronome : Metronome
    var objectifs : [Objectifs]

    init() {
    self.parties = []
    self.metronome = Metronome()
    self.objectifs = []
    }
    }

    class Objectifs : Codable {
    var objectifs : [enumObjectifs]
    var metronome : Metronome
    var methode : Methode

    init() {
    self.objectifs = []
    self.metronome = Metronome()
    self.methode = Methode()
    }
    }

    class Methode : Codable {
    var actions : [Actions]
    var temps : Temps
    var nombreRepetition : Int // NombreRepetitions
    var metronome : Metronome

    init() {
    self.actions = []
    self.temps = .j1
    self.nombreRepetition = 0
    self.metronome = Metronome()
    }
    }

    class Metronome : Codable {
    var tempo : Int
    var rythme : RythmeDeReference

    init() {
    self.tempo = 0
    self.rythme = .croche
    }
    }

    class PointsDAttention: Codable {
    var texte : [AttentionsTexte]
    var corps : [AttentionsCorps]
    var interpretation : String

    init() {
    self.texte = []
    self.corps = []
    self.interpretation = ""
    }
    }

    /* *********************************** */

    enum enumParties : String, Codable {
    case A = "A"
    case B = "B"
    case C = "C"
    case D = "D"
    case Ap = "A'"
    case Bp = "B'"
    case Cp = "C'"
    case Dp = "D'"
    case Int = "Int."
    case Coda = "Coda"
    case Mont = "Mont."
    case Desc = "Desc."
    case p1 = "[1]"
    case p2 = "[2]"
    case pFin = "[-"
    case pDeb = "-]"
    case smile = "fa-smile-o"
    case leaf = "fa-leaf"
    case sun = "fa-sun-o"
    case heart = "fa-heart-o"

    static let allValues = [A, B, C, D,
    Ap, Bp, Cp, Dp,
    Int, Coda, Mont, Desc,
    p1, p2, pFin, pDeb,
    smile, leaf, sun, heart]

    }

    enum RythmeDeReference : String, Codable {
    case noire = "Noire"
    case croche = "Croche"
    }

    enum enumObjectifs : String, Codable {
    case MEns = "MEns."
    case MSep = "MSep."
    case ParCoeur = "PCoeur"

    static let allValues = [MEns, MSep, ParCoeur]

    }

    enum Actions : String, Codable {
    case Lire = "Lire"
    case Chanter = "Chanter"
    case Jouer = "Jouer"
    case Taper = "Taper"

    static let allValues = [Lire, Chanter, Jouer, Taper]

    }

    enum Temps : String, Codable {
    case TLJ = "TLJ"
    case SuiteALaPrecedente = "Suite"
    case j1 = "1j"
    case j2 = "2j"
    case j3 = "3j"
    case j4 = "4j"

    static let allValues = [TLJ, SuiteALaPrecedente, j1, j2, j3, j4]

    }

    enum AttentionsTexte : String, Codable {
    case Doigté = "Doigté"
    case Concentration = "Concentration"
    case Lecture = "Lecture"
    case Book = "fa-book"

    static let allValues = [Doigté, Concentration, Lecture, Book]

    }

    enum AttentionsCorps : String, Codable {
    case Doigts = "fa-hand-pointer-o"
    case Ecoute = "fa-deaf"
    case Spock = "fa-hand-spock-o"
    case Epaules = "ico-epaule"
    case Dos = "Dos"
    case Bras = "Bras"

    static let allValues = [Doigts, Ecoute, Spock, Epaules, Dos, Bras]

    }




Connectez-vous ou Inscrivez-vous pour répondre.