Realm - navigation entre plusieurs tableViews - gestion des données

Bonsoir à tous!

Je suis confronté à un problème dans mon app et voilà quelques jours que je me prends la tête sans trouver la solution et ça commence à me rendre fou :smile:.

Le principe est simple, il s’agit denaviguer entre plusieurs tableView en affichant un contenu sélectif :
Je crée une liste de “programmes” dont j’affiche les noms dans une première tableView.
Lorsque je sélectionne un programme dans cette première tableView, je suis dirigé vers une deuxième tableView qui affiche les noms des “Exercices” contenus dans le programme sélectionné.

Si j’avais sélectionné un autre Programme dans la première tableView, la seconde tableView aurait donc affiché une autre liste d’Exercices…

Pour cela, j’ai crée plusieurs classes pour gérer mes objets Programme et Exercice :
La base de donnée est gérée avec Realm.

import Foundation
import RealmSwift

class Exercise:Object {
    @objc dynamic private var _name:String = ""
    
    var name: String {
        get {
            return _name
        } set {
            realm?.beginWrite()
            _name = newValue
            try? realm?.commitWrite()
        }
    }
    
}

Puis :

import Foundation
import RealmSwift

class Programm:Object {
    
    @objc dynamic private var _programmName:String = ""
    
    var programmName:String {
        get {
            return _programmName
        } set {
            realm?.beginWrite()
            _programmName = newValue
            try? realm?.commitWrite()
        }
    }
    
    
}

Puis deux classes “Manager” pour la gestion dans Realm :

import Foundation
import RealmSwift

class ProgrammManager {
    
    private var _realm:Realm
    private var _programmList:Results<Programm>
    
    
    
    init() {
        _realm = try! Realm()
        _programmList = _realm.objects(Programm.self)
    }
    
    
    func addNewProgramm(newProgrammName:String) -> Programm {
        let newProgramm:Programm = Programm()
        
        newProgramm.programmName = newProgrammName
        
        try? _realm.write {
            _realm.add(newProgramm)
            print(newProgramm.programmName)
        }
        return newProgramm
    }
    
    
    func deleteProgramm(atIndex index:Int)  {
        if let programmToDelete:Programm = getProgramm(atIndex: index) {
            try? _realm.write {
                _realm.delete(programmToDelete)
            }
        }
    }
    
    
    func getProgramm(atIndex index:Int) -> Programm? {
        guard index >= 0 && index < getProgrammCount() else {
            return nil
        }
        return _programmList[index]
    }
    
    func getProgrammCount() -> Int {
        return _programmList.count
    }
    
}

Le code est similaire pour la gestion des objets “Exercices”.

Mes vues se présentent comme suit :

  • Au lancement de l’app, on arrive directement sur la tableView affichant la liste des Programmes déja enregistrés, et dans la navigation bar, il y a un “+” pour ajouter un nouveau programme.
  • Lorsque l’on clique sur le “+”, on est dirigé vers une vue nous demandant de saisir le nom du nouveau programme.
  • Une fois cela fait, on clique sur OK (ce qui sauvegarde le nouveau programme) et on est dirigés vers la 2e tableView, dont je veux qu’elle affiche la liste des Exercices déjà enregistrés. Dans la Navigation bar, toujours un bouton “+” pour enregistrer un nouvel Exercice.

Le problème auquel je suis confronté est que lorsque je crée des exercices, ils s’affichent tous dans la même tableView, je ne parviens pas à les séparer en fonction du Programme précédemment sélectionné.
En effet, tous les objets de la classe Exercice sont stockés dans la même base de donnée Realm…

Je ne sais pas si je suis bien clair… ^^

N’hésitez pas si vous avez besoin de plus d’informations, et merci de votre aide!!

Guillaume

Pas encore de réponse, mais j’essaie d’avancer de mon coté :
J’essaie de me débrouiller comme suit mais j’ai encore des soucis.

J’ai ajouté une variable “programID” aux objets Exercice, qui stocke le nom du programme dont il est issu.
Le but étant ensuite de trier mes exercices dans ma tableView en fonction de la valeur (chaine de caractère) stockée dans “programID”
Cette valeur est bien récupérée dans ma base de données Realm, à coté des autres variables associées à cet exercice.

Cependant je ne parviens pas à faire une requête Realm pour trier ce qui est contenu uniquement dans une des variables (programID) des objets Exercice…

Bonjour,

Peut être que la solution serait d’avoir une seule database Realm avec tous les programmes et tous les exercices.
et ensuite quand tu as besoin des exos du programme X, tu utilises la notion de .filter de Realm sur le programme sélectionné.
c’est surement le plus simple vs d’avoir des tables croisées avec la notion de lien.
A+

Bonjour, merci pour ta réponse!

En fait les deux types d’objets sont déjà dans une seule base de données, il y a simplemét deux classes.

Lors d’un .filter, je parviens à sélectionner mes objets par le nom de leur variable, pas mar leur contenu…

Si je fais comme tu dis et que je fais ensuite un .filter des exercices du programe X, il faudra de toute façon que je sonde l’intérieur d’une variable, et pas seulement son nom, non?

Je suis pris ce matin, je regarde ca cet après midi et je te fais un retour avant ce soir.
En ce moment, je me suis mis a tester Firebase et Firestore :wink:

1 « J'aime »

J’utilise également Firebase dans tous mes projets donc, désolé, mais je ne peux pas trop aider :confused:

@baptiste_u2 merci! :slight_smile:

@schtipoun si Firebase propose une solution à mon problème je pourrais y jetter un oeil aussi ^^

Ah bah je sais exactement comment régler ton problème sur Firebase mais ça demande de revoir l’intégralité de la gestion des données de ton application donc c’est peut-être un peu radical comme solution !
Surtout si des personnes réussissent à t’aider sur Realm.

C’est ce que je me dis aussi haha.

Ce que je me dis aussi c’est que j’ai pas l’impression de vouloir faire quelque chose d’exceptionnellement rare dans mon app… ça me semble même très banal!

Il doit y avoir un truc tout simple que je ne pige pas avec Realm… :thinking:

Oui c’est clair que ton problème est assez “basique” et qu’il y a certainement quelque chose de tout simple pour y arriver !
Bon courage en tout cas :slight_smile:

1 « J'aime »

Guillaume,

Selon moi la méthode la plus propre serait d’utiliser les notions de relations entre classe : Many to One ou many to Many…qui sont expliquées dans la doc Realm.
Mais je ne les maitrise pas, donc je suis parti sur une truc avec une seule classe qui contient 3 propriétés : le nom du prog, le nom de l’ex et une dernière propriété avec yes or no dedans qui me permet de faire tous les filtres qui vont bien pour la 1ere TV (celle ou il y a juste des prog)

Je ne suis pas encore très expérimenté donc le code n’est pas très propre mais je pense que cela marche.
Je te laisse regarder : https://github.com/Mike4ftv/ProgetExo

Nota : j’ai fait simple, si tu dois l’utiliser il faudra bien mettre tous les contrôles qui vont bien un peu partout (if let, guard let,…)

A+

1 « J'aime »

Merci beaucoup pour ta réponse Baptiste, je vais jeter un oeil attentif à ces notions de Many to One / Many to many car je n’en ai encore pas entendu parler!

Et merci beaucoup pour ton dépôt Git, je vais de ce pas l’observer!

Je vous donnerai des nouvelles lorsque j’aurai débloqué tout ça ^^

Guillaume

Wouhou victoire!!
Merci beaucoup, j’ai adapté ta solution sans vraiment changer grand chose dans mon code, et ça y est j’ai enfin une bonne sélection des exercices lorsque je clique sur un programme donné!!

En revenche, j’ai repéré quelque chose d’étrange dans ma base de données Realm, que j’observe en temps réel lorsque je manipule les objets “Exercice” :

Supposons que je crée, dans le programme 1, l’exercice 1 puis l’exercice 2.
Ensuite, dans un programme 2, je crée l’exercice 3 et l’exercice 4.
Dans ma base de données, dans les objets Exercice, j’ai donc dans l’ordre 1, 2, 3, 4.

Lorsque je décide de supprimer l’exercice 2 (donc en me rendant dans le programme 1), l’exercice 2 est bien supprimé de ma base de données sans crash, mais… mon exercice 4 se retrouve à la place de l’exercice 2…
J’ai alors dans l’ordre les exercices 1, 4, 3…

Étrange, non? Je ne comprends pas pourquoi l’ordre dans ma bas de donnée est changé.
Le problème est que forcément, cela occasionne des désordres dans les indexPath / indexPath.row, et lorsque je veux supprimer ensuite l’exercice 4, celui ci n’est pas à la position attendue, et j’ai un crash…

J’ai regardé un peu et il semble que les requetes .filter ne soient pas ordonnées par défaut, ce qui explique que l’ordre puisse changer… pas pratique, mais soit.

Apparemment, faire un .sorted sur un .filter est possible et résout le problème.

J’ai regardé la doc sur le many to one et le many to many, c’est très intéressant…

Ce truc est une galère infernale, c’est compliqué de gérer les données Realm dans la database telle quelle, l’ordre change tout le temps dès que l’on supprime un objet, et les indexPath.row ne correspondent plus à rien, il faut recharger la tableView sans arrêt, trier dans tous les sens, et cela occasionne plein de bugs un peu partout.

Et je ne parle là que de la gestion des exercices dans un seul et même programme. Dès qu’on joue avec un second programme, c’est la cata…

Je vais donc tout remettre à plat, j’ai trouvé un tuto sur youtube qui explique pas mal comment tout compartimenter, mettre chaque jeu de données dans un Array ou une List, séparément, afin de conserver l’ordre et surtout que les données ne se mélangent jamais…

Je continue mon chemin, ça commence à être long mais je vais y arriver et peut être que ça servira à quelqu’un d’autre un jour ^^