[Résolu] CoreData : Max 100 attributes

busterTheobusterTheo Membre
septembre 2015 modifié dans Dev. iOS, watchOS, tvOS #1

Bonjour,


ma base de données (entity coreData) contient d'avantage que 100 champs (attributs). Je ne parle pas de combien j'ai d'enregistrements, puisque cela se fera par l'utilisateur. Non je parle bien de "fields" dans le sens d'une bd mySql par ex.


 


Et, donc j'ai ce message d'erreur (panneau jaune) :



 


xcdatamodel: Patients has more than 100 properties; consider a more shallow entity hierarchy or denormalized properties



 


Le message parle de properties alors qu'il s'agit de attributes (ça s'appelle comme ça dans le xcdatamodel)


 


J'ai cherché partout, et j'ai l'impression que je peux rester comme ça (j'aurai en gros moins de 300 attributes). Tout ce que j'ai vu, c'est au sujet des relationshpis dont je ne me sers pas pour l'instant...


 


C'est bizarre que l'on soit limité en nombre de champs.


 


Merci si quelqu'un a une idée...


 


 


Mots clés:
«1

Réponses

  • 300 propriétés par entité ? 


    Je serai toi je reverrai un peu ma conception...


    Tu sais nous monter ça ?


  • C'est un warning apparemment d'après mes recherches.


     


    Maintenant, il serait peut-être plus intéressant de "diviser" tes modèles...



  •  


     


    Merci pour vos réponses

    300 propriétés par entité

    Ben oui.


     


    Une application avec en gros 40 écrans avec chacun entre 7 et 10 variables à  stocker dans une bdd.


    Rien d'exceptionnel.


     


    Voir un exemple ancien mais explicatif ici


     


    Il faut stocker les positions des poignées, les contenus des champs (à  droite), les valeurs de zoom et de position de l'image, etc.


    Tout ça sur 40 écran. Logique non !


     



     


     


    C'est un warning apparemment d'après mes recherches

    Ouais, j'avais vu ça. Mais est-ce que je dois modifier cela ?


    Parce que c'est quand même fort de café d'être limité en nbre de champs...


     



     


     


    Maintenant, il serait peut-être plus intéressant de "diviser" tes modèles

    Je me dis que je n'ai que cette solution. Dommage.


  • LarmeLarme Membre
    septembre 2015 modifié #5


    Il faut stocker les positions des poignées, les contenus des champs (à  droite), les valeurs de zoom et de position de l'image, etc.


    Tout ça sur 40 écran. Logique non !




    Non.


    Pour retrouver une data dans un objet qui possède 300 attributs, c'est un peu chiant.


    J'ai vu vite fait la vidéo, mais si déjà  tu charges les données de la photo de profil qui est liée à  la personne, c'est déjà  beaucoup moins lourd comme objet que de charger la personne et toutes ses photos et données qui vont avec. Chaque photo peut avoir son zoom, son offset, etc.


  • Si tu te sert de Core Data "uniquement" pour faire le stockage des paramètres peut être pourrais tu rassembler tous ces paramètres au seins d'un simple NSMutableDictionary que tu peux sauver dans CoreData sous la forme d'un 'Binard Data'. Du coup tu auras beaucoup moins d'éléments à  sauvegarder.

  • Je m'associe à  Larme dans l'idée de morceler les données.


    Pour aller plus loin si tu a 40 écrans tu as déjà  40 sous-ensembles de données. A toi de voir comment sont articulées les données entre elles pour optimiser le tout.


     


    La c'est un peu comme mettre toutes tes courses de la semaines dans le même emballage...


  • AliGatorAliGator Membre, Modérateur
    Oula oui si tu as une entité avec plus de 100 attributs/propriétés c'est qu'il est grand temps de revoir ta structure et de morceler toi ça pour rendre ça plus propre.

    Tant pour la lisibilité de ton modèle d'un côté que pour les performances (car si tu charges un objet CoreData avec 100 attributs alors que pour ton écran tu n'en utilises que 4 mes 96 autres seront quand même fetchés dans la base pour rien en plus !!)



    Imagine, même hors CoreData, que tu veux d'écrire un octogone, défini par 8 coordonnées x et y et une couleur pour chaque sommet. Toi d'après ce que j'ai compris t'es un peu parti pour créer dans ton modèle (que ce soit une entité CoreData ou une classe NSObject classique) à  définir 24 propriétés, que sont x1, y1, color1, x2, y2, color2, etc...!! Voire bien pire j'ai peur que tu sois même dans l'optique de définir 48 propriétés a ton objet, x1,y1,r1,g1,b1,x2,y2,r2,g2,b2,...


    Non seulement ça devient vite volumineux et mal organisé mais en plus tu ne représentes pas tes points de manière individuelle.


    Il est plus logique de dire qu'un octogone est composé de 8 points, et qu'un point est composé d'un x, d'un y, et d'une couleur, et qu'une couleur est composée d'une valeur rouge, vert et bleu. Tu décomposes ainsi ton modèle en objets plus petit, et ton octogone n'a plus que 8 propriétés, sommet1, sommet2, ... sommet8 (bon idéalement il a plutôt une propriété de type NSArray contenant un tableau de points, mais bon)


    Non seulement ça découpe ton modèle, le rend plus lisible, allège la récupération en base, mais en plus comme ça tu peux aussi facilement faire des méthodes qui travaillent sur les sous-éléments de ton modèle comme une méthode qui prend un objet Point en paramètre.


    Avoir un objet modèle qui a plus de 30 propriétés / attributs CoreData, c'est se tirer une balle. Et encore je dis 30 mais je dépasse rarement les 10-15. Au delà  y'a toujours moyen de découper.
  • Merci pour toutes vos remarques.


     


    Je vais donc couper mon entity en 6 entity par ex.


     


    Je m'entraine d'abord sur mon entity de base, et seulement sur un attribut.


    Cela fonctionnait lorsque l'attribut était rempli. (un string)


     


    Mais sur un nouvel enregistrement (donc l(attribut vide) j'ai un problème avec toujours ce satané nil, optionnel, etc.


     


     


     


    Donc, quand je tape sur le tableview, pour ne pas stocker mes 300 variables, je stocke le indexPath.row.



    listeDesVariables.patientNumber = indexPath.row

    Ainsi, dans chacun de mes écran, je peux faire cela.



    let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    let fetchRequest = NSFetchRequest(entityName: "Patients")

    if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [Patients] {
    if fetchResults.count != 0 {
    println("fetchResults.count = \(fetchResults.count)")
    println("fetchResults[listeDesVariables.patientNumber] = \(fetchResults[listeDesVariables.patientNumber])")
    }
    }

    J'ai bien en sortie :



     


    fetchResults[listeDesVariables.patientNumber] = <Patients: 0x7fdc33102ab0> (entity: Patients; id: 0xd000000000040000 <x-coredata://46D175EB-F2B8-41DB-BF38-3DE7495F8B76/Patients/p1> ; data: {


     age = "";


    etc


    etc


    e2L1LigneSourire = nil;


    etc


    etc


    })



     


    ou bien :



     


     


    e2L1LigneSourire = "toto;

     


    si j'avais enregistré le champ auparavant.


     


    Mais dans le cas ou il est vide, l'attribut est donc à  nil (normal) (e2L1LigneSourire = nil;)


     


    Et si j'essaie de faire cela, 



    if fetchResults[listeDesVariables.patientNumber].e2L1LigneSourire != nil {
    listeDesVariables.e2L1LigneSourireString = fetchResults[listeDesVariables.patientNumber].e2L1LigneSourire as String!
    }

    j'ai le message "Int is not convertible to Range<Int>" , alors que ça fonctionne bien si l'attribut = "toto" par ex, mais si il est nil, je ne peux pas tester s'il est nil ou pas nil : c'est bizarre ce truc. Y'a un truc qui m'échappe. Je croyais avoir bien compris le test du nil.


     


    J'ai essayé aussi avec



    fetchResults[0].e2L1LigneSourire

    ou 



    if fetchResults[listeDesVariables.patientNumber].e2L1LigneSourire as String! != nil

    ou encore tout un tas de chose.


     


    J'ai la plupart du temps l'erreur à  la compilation.


     


    Et quand ça passe, ça plante quand je vais sur l'écran. Sans message d'erreur.


     


    Voilà , j'ai cherché partout sur le web, et je ne trouve rien qui m'aide.


     


    Une idée ?

  • Bon, en fait, on oublie tout ça. Le plan de stocker l'index ça marche pas. Et c'est logique je ne m'éttend pas.


     


    Je repose ma question autrement.


     


    Lorsque je clique sur mon tableview,  à  l'aide de ça (classique)



    if let indexPath = self.listePatients.indexPathForSelectedRow() {
    let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject

    et ça (par ex)



    let nom = object.valueForKey("nom") as! String

    et évidemment les 80 lignes Apple (coreData) :



    var fetchedResultsController: NSFetchedResultsController {
    etc
    }

    var _fetchedResultsController: NSFetchedResultsController? = nil

    func controllerWillChangeContent(controller: NSFetchedResultsController) {
    etc
    }

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
    etc
    }

    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    etc
    }

    func controllerDidChangeContent(controller: NSFetchedResultsController) {
    etc
    }

    dans lesquelles sont spécifiées l'entity et le tableView (classique)


     


     


     


    je récupère bien mes variables.


     


    Jusque là , tout va bien.


     


    Maintenant, si mes autres variables (celles des autres écrans) sont dans une autre entity (ce que je dois faire pour avoir des petites entity), comment dois-je faire (sur un autre écran) pour récupérer les variables correspondantes au même indexPath ?


     


    J'ai essayé des centaines de trucs, vu plein de autos, et je ne comprend vraiment pas.


     


    Ok à  partir du tableview, on extrait de l'entity à  partir de l'indexPath, mais quand on n'est plus dans un tableView, comment extraire, puisque l'on n'a pas l'index dans le coreData?


     


    Merci d'avance


  • sinon il y a aussi Magical Record !!!!



  •  


     


    sinon il y a aussi Magical Record !!!!

    C'est sympa, mais j'ai pas trop le niveau, et en plus c'est en objC/


     


    Comment connaà®tre le numéro d'enregistrement d'une fiche dans coreData ?


  • Alors, on va réfléchir à  comment faire.


    Je n'ai pas la solution finale et la plus optimisée, et je ne sais pas comment est architecturée ton application.


     


    Cependant, admettons tu as une sorte de clé primaire (Id d'un patient), que tu récupères quand sélectionne un patient dans la UITableView.


    Tu le gardes, et quand tu arrives sur un écran, tu fais une recherche dessus.


     


    Example:


    Dans tableView:didSelectRowAtIndexPath:, tu gardes l'ID.


    Dans un écran, tu fais une recherche avec le prédicat sur cet ID: SELF.idPatient == searchedId sur la table contenant les attributs que tu veux.


    Dans un autre écran, pareil.


  • AliGatorAliGator Membre, Modérateur
    OMG j'avais oublié à  quel point CoreData était compliqué sans MagicalRecord ^^ que de lignes de code qui se simplifieraient tellement avec MR ;-)

  •  


     


    Cependant, admettons tu as une sorte de clé primaire

    Oui, tu as vu juste, c'est ce que j'essaie de faire. Tu proposes donc (j'hésitais), que, dans chacune de mes entity, j'ai un champ id, qui sera le même dans toutes mes entity. En gros comme dans une bd classique mysql. Et à  chaque écran, une recherche sur l'id et hop...


     


    Je crois que c'est la meilleure solution, dans la mesure (chose que je ne parviens pas à  admettre) où il est impossible de récupérer le numéro d'enregistrement dans la première entity (celle qui montera à  partir du tableview), on n'a pas le choix : on se le crée dans chacune des entity (des tables - au sens mysql).


     


    Je faisais également des essais avec les relationships, mais j'ai un peu du mal. à‰galement avec les entity child/parent...


     


    Merci pour tes remarques judicieuses.


  • Ah non, au temps pour moi, je me suis planté dans ce que je voulais dire.


    Je voulais au départ écrire: SELF.patient.idPatient


    Lié l'objet de la page à  un patient, qui lui a un ID. Sinon, tu vas répéter à  trop de fois inutilement un champ idPatient...


  • AliGatorAliGator Membre, Modérateur
    Ne surtout pas répéter les identifiants dans toutes les tables : cela ne sert à  rien, prend de la place inutilement, et tu perds toute la puissance de CoreData qui est un Graphe Objets / une BDD relationnelle et non pas une bête base SQL.

    Les relationships c'est fait pour ça même les one-to-one.
  • Si tu divises ta grosse entity en plusieurs sous-entity, tu dois impérativement utiliser les relationships.


    Par ailleurs (je répète ce que j'ai entendu), il est déconseillé d'utiliser les Parent/child relationships. Une histoire de comment cette fonctionnalité est implémentée en sql. Je trouve dingue et si quelqu'un sur ce forum me disait le contraire (que, non, c'est OK de les utiliser) je serai bien content de l'entendre. Perso, j'utilise cette fonctionnalité (j'ai sû trop tard que c'etait déconseillé).
  • Bon, je me suis créé un nouveau projet pour jouer avec coreData et les relationShips.


     


    Je me suis refait les vidéos et les tutos sur le sujet. Chaud.


     


    J'avance bien, mais...


     


    J'ai mis en ligne le projet, ce sera plus simple.


     


     


     


    En gros :


    Un tableView (ListePatients) avec nom - prénom - sexe - Et un add new patient (la première entity)


     


    Puis si didSelectRowAtIndexPath, j'affiche la fiche du patient (FichePatient) qui contient un add pour ajouter les nouveaux champs dans le fameux nouveau entity (Etape1) - Avec le push vers le (NouvelleEtape1)


     


    Tout marche nickel - Y'a un (println("etape1 = \(etape1)")) qui affiche bien le nouvel enregistrement dans l'entity Etape1.


     


    Mon soucis est dans l'affichage de la fiche patient (FichePatient)


     


    J'essaie de récupérer les champs de l'entity Patiens (ok) mais pour ceux de l'entity Etape1, je galère cher.


     


    Encore à  cause du nil.


     


     


    Dans mon vrai projet, je ne vais quand même pas, lors de l'enregistrement du premier écran, enregistrer toutes les autres entity et leurs champs à  "" pour ne pas avoir de nil.


    Y'a un truc qui m'échappe. Dommage, car je ne suis pas loin, mais je bloque.


     


    Merci our votre aide précieuse.

  • Je parviens à  faire enfin un truc intéressant.


     


    Dans FichePatient.



    nomFiche.text = nomFicheString
    prenomFiche.text = prenomFicheString
    sexeFiche.text = sexeFicheString

    let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let context: NSManagedObjectContext = appDel.managedObjectContext!
    let entityDescription = NSEntityDescription.entityForName("Patients", inManagedObjectContext: context)

    let fetchRequest: NSFetchRequest = NSFetchRequest()
    fetchRequest.entity = entityDescription
    fetchRequest.returnsObjectsAsFaults = false
    let predicate: NSPredicate = NSPredicate(format: "nom == '\(nomFicheString)'")
    fetchRequest.predicate = predicate
    let fetchResults: NSArray = context.executeFetchRequest(fetchRequest, error: nil)!

    let singlePatient: Patients = fetchResults.lastObject as! Patients

    let etape1 = singlePatient.etape1

    poignee1Fiche.text = etape1.poignee1
    poignee2Fiche.text = etape1.poignee2
    poignee3Fiche.text = etape1.poignee3
    poignee4Fiche.text = etape1.poignee4
    poignee5Fiche.text = etape1.poignee5

    J'ai bien les deux entity pour chaque enregistrement.


  • colas_colas_ Membre
    septembre 2015 modifié #21
    Comme tu as maintenant n entités, il faut que tu les crées toutes. Ce n'est parce que tu crées l'entite parente que les filles sont créées automatiquement.
  • Attention, le modèle de donnée n'est pas censé être impacté par la vue. C'est pas logique d'avoir une relation qui se nomme étape 1. ça veut rien dire d'un point de vue modèle de donnée l'étape 1.


     


    Tu es censé organiser tes données par groupe logique du point de vue données en elle même. Et les nommer en fonction.


  • busterTheobusterTheo Membre
    septembre 2015 modifié #23

     


     


    Comme tu as maintenant n entités, il faut que tu les crées toutes. Ce n'est parce que tu crées l'entite parente que les filles sont créées automatiquement.

    Je suis justement, dans mon vrai projet, en train de faire cela. Quel boulot...


    Je prend mon temps, pour bien créer les bonnes entités pour chacun de mes écrans ou bien chacun de mes groupes (pageviews) d'écran.


     


    Je n'aurai pas d'entité parente. Je dois avoir une entité en relationship avec plusieurs autres. Tout ça en one to one.


    Chacune des autres entités ne sera en relation qu'avec la première


     



     


     


    C'est pas logique d'avoir une relation qui se nomme étape 1. ça veut rien dire d'un point de vue modèle de donnée l'étape 1

     


    C(était juste un test.


    Mais en attendant, mon projet comporte des écrans qui se nomment justement étape1, 2, etc.


    Avec en plus, comme c'est dans des pageViews, y'a aussi des étape1Level1,  Level2, 3, etc.


     


    Comme j'associe une entité à  un écran (ou un groupe d'écrans) , pour ne la charger que quand je suis dans cet écran (ou ce groupe), il me semble logique que je la nomme d'un nom associé littéralement aux écrans concernés, non !!!


     



     


     


    Tu es censé organiser tes données par groupe logique du point de vue données en elle même. Et les nommer en fonction

    C'est exactement ce que je fais, comme je l'explique ci-dessous.


     


    Merci d'avoir pris le temps de se plonger là -dedans, et merci pour vos remarques, cela me réconforte.


     


    En attendant, j'ai modifié le projet test, déposé plus haut en pièce jointe.


    En fait, lorsque j'enregistre la première entité (premier écran, donc), j'enregistre également la seconde entité (étape1 dans ce cas), avec les chats à  "". Comme ça c'est jamais nil - Ouf


     


    La modif concerne le fichier "NouveauPatient" et c'est dans l'action du bouton save :


    Voici le code si quelqu'un le désire.


    Et là , je n'ai plus aucune erreur.



    @IBAction func saveButton(sender: AnyObject) {
    var appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    var context: NSManagedObjectContext = appDel.managedObjectContext!
    let entityDescriptionPatient = NSEntityDescription.entityForName("Patients", inManagedObjectContext: context)

    newPatient = Patients(entity: entityDescriptionPatient!, insertIntoManagedObjectContext: context) as Patients
    newPatient.nom = nomTextField.text
    newPatient.prenom = prenomTextField.text
    newPatient.sexe = sexeTextField.text

    let entityDescriptionEtape1 = NSEntityDescription.entityForName("Etape1", inManagedObjectContext: context)
    newEtape1 = Etape1(entity: entityDescriptionEtape1!, insertIntoManagedObjectContext: context) as Etape1

    newEtape1.poignee1 = ""
    newEtape1.poignee2 = ""
    newEtape1.poignee3 = ""
    newEtape1.poignee4 = ""
    newEtape1.poignee5 = ""

    newPatient.etape1 = newEtape1

    context.save(nil)

    self.navigationController?.popViewControllerAnimated(true)
    }

  • AliGatorAliGator Membre, Modérateur

    Comme j'associe une entité à  un écran (ou un groupe d'écrans) , pour ne la charger que quand je suis dans cet écran (ou ce groupe), il me semble logique que je la nomme d'un nom associé littéralement aux écrans concernés, non !!!

    Non carrément pas, faire ça serait contre les principes de base du pattern MVC


  •  


    Mais en attendant, mon projet comporte des écrans qui se nomment justement étape1, 2, etc.


    Avec en plus, comme c'est dans des pageViews, y'a aussi des étape1Level1,  Level2, 3, etc.


     


    Comme j'associe une entité à  un écran (ou un groupe d'écrans) , pour ne la charger que quand je suis dans cet écran (ou ce groupe), il me semble logique que je la nomme d'un nom associé littéralement aux écrans concernés, non !!!


     


    C'est exactement ce que je fais, comme je l'explique ci-dessous.




     


    Ce que veulent te dire Yoann et AliGator c'est que justement cette similarité de logique est suspecte.


    Si la structure de ton modèle de données est expliqué par la logique d'un enchaà®nement de vue c'est qu'il est vraisemblable que le pattern MVC n'est pas respecté ; plus précisément que la partie M (Modèle, c'est à  dire ta structure de données) est vraisemblablement trop dépendante de la partie C (Contrôleur, l'enchaà®nement des vues).


     


    Si nous ne nous trompons pas, la conséquence sera que ton application pourra devenir compliquée à  maintenir lorsque tu voudras ajouter d'autres fonctionnalités car ton modèle de données pourrait être trop lié aux fonctionnalités actuelles de l'application.

  • Oui.


     


    Il faut quand même faire respirer ton code, le modéliser un minimum pour que toi comme d'autres puissent le comprendre et le modifier plus facilement.


     


    Quand je vois le code ci-dessus par exemple, je pense que tu peux l'améliorer significativement avec des méthodes simples comme les suivantes :


     


    1. Créer des extensions ou catégories en Objective-c de tes NSManagedObject pour y insérer le model, au moins le CRUD que tu sembles utiliser. Ainsi, tu devrais y ajouter une méthode qui ajoute, modifie, supprime et récupère des données. Tu peux fragmenter ceci en d'autres méthodes pour te permettre de récupérer plus facilement le Managed Object Context, créer une nouvelle entité etc.. 


     


    2. Mettre le nom de tes entités en temps que constante pour une meilleure modularité.


     


    3. à‰viter le Franglais.


     


    4. Préférer l'optional binding et des messages d'erreurs explicites aux Forced unwrapping.


     


    5. Ne pas mélanger la logique métier à  celui du model, ce qui rejoint le 1. ci-dessus. Essayer de respecter une architecture MVC ou plus adapté ici MVVM.


     


    6. à‰viter une trop forte dépendance à  l'AppDelegate (D'après Céroce et d'autres ici) même si ça reste discutable pour certains projets selon moi.


  • Souvent, les écrans sont liés au modèle, quand même !


     


    Exemple : un écran est lié au sourire, un autre écran est lié au nez. Cette séparation en écrans vient du modèle, qui ici sera :


     


    Patient :


    Nom


    Date de naissance


    Sourire


    Nez


     


    et ensuite,


     


    Sourire :


    coordonnées gauche


    coordonnées droite


     


    Nez :


    Angle


     


     


    Donc, je dirai surtout que c'est un problème de terminologie. Appeler une relationship etape1, c'est clairement une mauvaise idée.


    Tu devrais plutôt l'appeler sourire !


     


    Ensuite, il est possible que ta découpe de ta grosse entité en plusieurs entités ne recoupe pas exactement tes écrans. 


  • Bonjour à  tous.


    Merci pour vos efforts. Je vois que je suis loin du compte, alors que je croyais être sur la bonne voie.


    En gros je n'ai rien compris.


     


    Je retiens une chose : j'ai un sérieux problème avec le pattern MVC.


    Je met ici, quand même, une version vidéo démo du vrai projet.


     



     


    Donc, je dirai surtout que c'est un problème de terminologie. Appeler une relationship etape1, c'est clairement une mauvaise idée.


    Tu devrais plutôt l'appeler sourire !



    Au vu de la démo, ça va être compliqué. Mais bon, c'est pas le plus grave.



     


     


    Ensuite, il est possible que ta découpe de ta grosse entité en plusieurs entités ne recoupe pas exactement tes écrans.

    Ben t'as raison, car j'ai quelques écrans avec environ 60 variables à  stocker : par ex l'étape 5 level 5 - l'écran des diastèmes.


    Je vais donc être obligé de faire plusieurs entités pour ce type d'écran. ça se complique grave.


    Dommage qu'on ne puisse pas faire une énorme entité (300 attributs) avec toutes mes variables, comme ce que j'ai fait jusqu'à  présent.


     



     


     


    1. Créer des extensions ou catégories en Objective-c de tes NSManagedObject pour y insérer le model, au moins le CRUD

    Tu veux dire regrouper les méthodes de CRUD dans une classe, comme elle fait dans cette vidéo  (part 2) ?


    Son fichier est SwiftCoreDataHelper. Elle le présente dans cette vidéo (part 1) à  la position à  6 minutes 02 secondes.



     


     


    2. Mettre le nom de tes entités en temps que constante pour une meilleure modularité.

    Tu parles de ça ?


    1-



    let entityDescriptionEtape1

    auquel cas, faut que je mette une Majuscule.


    Ou bien ça (le newEtape1)


    2-



    newEtape1 = Etape1(entity: entityDescriptionEtape1!, insertIntoManagedObjectContext: context) as Etape1

    Donc initialisé avec Let et bien sur une majuscule


     



     


     


    4. Préférer l'optional binding et des messages d'erreurs explicites aux Forced unwrapping

     


    Je viens de me refaire ces deux liens sur les optionnals, etc.


    Apple


    CoursSwift


     


    Je commence un peu à  comprendre. AliGator m'avait pourtant fait un super cours.


    Tu pourrais me dire à  quel endroit ça cloche dans mon code ?


     



     


    5. Ne pas mélanger la logique métier à  celui du model, ce qui rejoint le 1. ci-dessus. Essayer de respecter une architecture MVC ou plus adapté ici MVVM.


     


    6. à‰viter une trop forte dépendance à  l'AppDelegate (D'après Céroce et d'autres ici) même si ça reste discutable pour certains projets selon moi.



    Je pense être assez incompétent pour tout comprendre. Mais je garde ça en mémoire.


     



     


    Ce que veulent te dire Yoann et AliGator c'est que justement cette similarité de logique est suspecte.


    Si la structure de ton modèle de données est expliqué par la logique d'un enchaà®nement de vue c'est qu'il est vraisemblable que le pattern MVC n'est pas respecté ; plus précisément que la partie M (Modèle, c'est à  dire ta structure de données) est vraisemblablement trop dépendante de la partie C (Contrôleur, l'enchaà®nement des vues).


     


    Si nous ne nous trompons pas, la conséquence sera que ton application pourra devenir compliquée à  maintenir lorsque tu voudras ajouter d'autres fonctionnalités car ton modèle de données pourrait être trop lié aux fonctionnalités actuelles de l'application.



    J'avoue que je comprend pas trop, comment faire autrement. Quelle serait l'alternative à  un écran = un controller = une entité ?


     


    Merci d'avance...


  • AliGatorAliGator Membre, Modérateur
    septembre 2015 modifié #29

    Je retiens une chose : j'ai un sérieux problème avec le pattern MVC.



    Effectivement c'est sans doute surtout de ce côté qu'il faut te perfectionner

     



    Dommage qu'on ne puisse pas faire une énorme entité (300 attributs) avec toutes mes variables, comme ce que j'ai fait jusqu'à  présent.



    Faut pas le voir comme ça. Je dirais plutôt "Heureusement qu'on ne peut pas, car ça t'autoriserai à  faire n'importe quoi et surtout un modèle crade, et surtout ça génèrerai de sérieux problèmes de performances de ta base si pour rien qu'un seul enregistrement (pour chaque instance NSManagedObject) tu forçais du coup à  fetcher 300 champs dans ta base, ce qui commence a devenir coûteux.

     



    Je viens de me refaire ces deux liens sur les optionnals, etc.
    Apple
    CoursSwift


    Je commence un peu à  comprendre. AliGator m'avait pourtant fait un super cours.

    Tu pourrais me dire à  quel endroit ça cloche dans mon code ?



    Je t'invite aussi à  lire mon article de blog "Thinking un Swift: Saving Ponies" qui parle de pourquoi c'est mal d'utiliser à  tout bout de champ des "!" et comment les éviter.

     



    J'avoue que je comprend pas trop, comment faire autrement. Quelle serait l'alternative à  un écran = un controller = une entité ?



    Le plus adapté serait certainement :


    1) Soit passer ton graphe objet (ton objet Patient en cours de création + ses objets liés) a chaque étapeVC, pour que chaque étape remplisse juste les champs qui lui sont liés. Un peu comme si tu avais à  remplir un long formulaire mais que tu be remplissais que e que tu sais remplir et passait ensuite la feuille à  ton comptable pour qu'il remplisse les infos que tu connaissais pas sur ton numéro de client bancaire, puis que tu la passais à  ton juriste pour qu'il remplisse d'autres infos... chaque étape ca remplir juste ce qui la concerne. A la fin de toutes les étapes tu auras un objet rempli que tu pourras sauver en base CoreData seulement une fois arrivé tout au bout.


    2) Ou alors avoir des objets intermédiaires (un peu comme les ViewModels du pattern MVVM), très liés à  la vue et ton découpage UI, et t'en servir pour véhiculer les variables de chaque étape, et à  la fin (après la dernière étape quand tout est rempli) tu construits tes NSManagedObjects (Patient & co) à  partir de ces objets ViewModel et sauve dans CoreData. Ce qui est un peu comme la première solution mais avec des classes intermédiaires pour faire le pont entre UI et Modèle et que tu gardes une indépendance relative entre les 2.


  • Ou alors


    3) tu crées ton entité principale (ou fetch) au début du processus. J'imagine que tous tes VC qui remplissent les infos sont chapeautés par un VC (sinon, tu mets ça dans un classe à  part, par exemple une share de instance (un singleton)). Dans ce VC en chef, ou dans Le singleton créé pour ça (tu peux l'appeler MyFormAssistant) tu gardes une référence au nsmanagedobject en chef (celui qui correspond au patient). Dans MyFormAssistant, tu crées des méthodes genre function getOrCreateRelatedSmileEntity() : ()-> NSManagedObject qui font ce que tu imagines.


    À chaque écran, tu appelles cette méthode (si tu la mets dans un singleton, tu peux l'appeler directement. Si c'est dans le VC parent, tu devras te trimballer une référence weak vers le parent dans chaque écran. Autant dire : le singleton semble mieux), tu remplis ce que tu veux, et tu peux sauver a chaque instant.


    Sinon, un outil génial pour coredata c'est mogenerator.

  •  


    Tu veux dire regrouper les méthodes de CRUD dans une classe, comme elle fait dans cette vidéo  (part 2) ?


    Son fichier est SwiftCoreDataHelper. Elle le présente dans cette vidéo (part 1) à  la position à  6 minutes 02 secondes.



     


    Pour schématiser, c'est définir un endroit pour gérer exclusivement les actions sur une entité. Tu peux crées une extension de Patients que tu peux organiser dans un nouveau fichier dans lequel tu mets les actions : addPatient, deletePatient, findPatient, allPatients etc. C'est à  toi de voir selon tes besoins. Cette méthode te permet de mieux découper ton modèle.


     


    Pour les constantes je parlais surtout du nom de l'entité :



    NSEntityDescription.entityForName("Patients", inManagedObjectContext: context)

    Patients est écris en dur or pour ma part je l'écrirais comme une constante puisque tu risques de l'utiliser de nombreuses fois. ça évite des erreurs et si demain tu veux modifier le nom de ton entité pour X raisons, tu ne le fais qu'à  un seul endroit.


     



     


    Je viens de me refaire ces deux liens sur les optionnals, etc.


    Apple


    CoursSwift


     


    Je commence un peu à  comprendre. AliGator m'avait pourtant fait un super cours.


    Tu pourrais me dire à  quel endroit ça cloche dans mon code ?



     


    C'est partout où tu mets "!" tout simplement. Ou alors faut être absolument sur du cas. 


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