Realm, récupération de données sous forme de tableau

Suite du sujet Travailler avec les Realm Results<T> ou des List<T> ou encore des Array? :

Sur les conseils d’Alexandre, j’ai crée un nouveau sujet qui traite des tableaux sour Realm.

Je précise du coup ma question:
j’ai une classe coureurs:

class coureurs: Object {
@objc dynamic private var _name = «  »
@objc dynamic private var _prenom = «  »
@objc dynamic private var _number = «  »
}

ensuite, j’ai suivi le cours de Maxime.

var name:String {
get {
return _name
}
set {
_name = newValue
try? realm?.commitWrite()
}
}
etc.

Une équipe de coureur est composée de 4 à 6 coureurs et chacun donc à un numéro.
J’essaie de créer une app qui permet à une équipe de relais (4 coureurs en course max) de tester et trouver la configuration la plus efficace:
le coureur 1 en 1er dans le relais? Le coureur 4 en 1er? élève 6 ben 2ème position du relais?
Et ce avec l’aide précieuse de @Draken notamment.

Vous pouvez la tester pour comprendre:
https://itunes.apple.com/us/app/calc4relais/id1342164159?mt=8

Pour gagner du temps pour l’utilisateur, j’ai donc crée la classe coureur et une classe course. Lorsqu’une nouvelle course est testée, l’utilisateur doit remplir le champ N° du coureur. Si le N° entré est le 4, alors automatiquement, ses données sont affichées (prénom, temps, etc.). Le problème c’est que si un numéro est entré et que ce numéro n’existe pas (aucun coureur de la classe coureur n’a ce numéro… ) et bien ça crash! Evidemment!
Je veux donc récupérer sous forme de tableau la liste des coureurs crées pour tester si le numéro entré existe bien.
J’ai essayé ça:
let _coureur = coureurs()
// puis dans une fonction dans laquelle je veux utiliser le tableau des numéros de mes coureurs:
let coureurNumber = [_coureur.number] mais ça ne marche pas.

Voici la réponse d’@Alexandre:
"D’abord, que retourne coureurs() ? Un tableau de tous les coureurs ?
_Si oui, et que tu souhaites récupérer le numéro d’un coureur dans le tableau de tes coureurs (coureur), tu devrais plutôt faire:

_let coureurNumber = coureur[index].number // où index est le numéro du coureur que tu souhaites atteindre"

coureurs() me permet d’hériter de mes coureurs enregistrés si j’ai bien tout compris. Et donc des attributs des coureurs. Mais impossible de crée un tableau des « numbers » de chaque coureur.

Plus simplement, je veux tester si le n° de coureur entré dans la course est bien compris dans la liste des numéros de coureurs de l’équipe qui court! Si oui, affichage de ses données, sinon, UIAlertController!

Y[quote=“jeancharles.bidault, post:1, topic:1018”]
Le problème c’est que si un numéro est entré et que ce numéro n’existe pas (aucun coureur de la classe coureur n’a ce numéro… ) et bien ça crash! Evidemment!
[/quote]
Pourquoi tu ne ferait pas comme ca :

Ton objet Realm :
class coureurs: Object {
@objc dynamic private var _name = “”
@objc dynamic private var _prenom = “”
@objc dynamic private var _number = “null”
}

Dans ton ClassManager :
let joueursAvecNumero = realm.objects(coureurs.self).filter(“_number != ‘null’”

Comme ça tu a as forcément une liste de coureur ayant un numéro.

ÉDIT : je viens de penser à un truc, il te faudra gérer la notion d’equipe dans le Results().filter(…)

Quand tu te poses ce genre de questions, vas regarder la documentation Apple, pour savoir si cela n’existe pas déjà. Tu verras que l’opérateur .contains() permet de tester la présence (ou l’absence) d’une valeur dans un tableau.

let listeNumerosCoureurs = [3, 13, 7, 12, 6]
let valeur = 12

if listeNumerosCoureurs.contains(valeur) {
    print ("C'est bon ..")
} else {
    print ("ALERTE ALERTE ! Valeur inexistante")
}

Bonjour à tous,

Merci @Draken pour ce retour. Je prends! Cepend’at, ta proposition d’avant fonctionnait aussi et mon problème viens plus de l’impossibilite Pour l’instant de créer un tableau contenant les numéros de chaque coureur créé.

Ce n’est pas bien difficile. Il suffit de parcourir le tableau des coureurs et d’enregistrer chaque numéro dans un nouveau tableau.

// Classe Coureur simplifiée
class Coureur {
        var nom = "nom"
        var identifiant = 0
        
        init(nom:String, identifiant:Int) {
            self.nom = nom
            self.identifiant = identifiant
        }
    }
    
    // Création d'une liste de coureurs pour le test
    func creerListeCoureurs() -> [Coureur] {
        var tableau = [Coureur]()
        tableau.append(Coureur(nom: "John",    identifiant: 12))
        tableau.append(Coureur(nom: "Eric",    identifiant: 7))
        tableau.append(Coureur(nom: "Pierre",  identifiant: 3))
        tableau.append(Coureur(nom: "Gabriel", identifiant: 1))
        return tableau
    }
    
    // Récupération des identifiants utilisés dans la liste des joueurs
    func creerListeIdentifiants(listeCoureurs:[Coureur]) -> [Int] {
        var listeIdentifiants = [Int]()
        for coureur in listeCoureurs {
            listeIdentifiants.append(coureur.identifiant)
        }
        return listeIdentifiants
    }

Mise en pratique :

    let listeCoureurs = creerListeCoureurs()
    let listeId = creerListeIdentifiants(listeCoureurs: listeCoureurs)
    print ("Liste identifiants : ", listeId)

Affichage :

Liste identifiants : [12, 7, 3, 1]


Une remarque : les conventions de nommage de Swift stipulent qu’il faut toujours commencer le nom d’une classe par une Majuscule, afin de distinguer facilement les classes et les variables dans le code.

Par pur curiosité, pourquoi vouloir charger un tableau plutôt que d’alimenter la base de données Realm ? Pour dès questions de performances ?

J’ai utilisé un tableau d’objets parce que je ne connais pas Realm. Je voulais un code simple et fonctionnel, pour tester la technique avant de poster. Charge à Jean Charles de comprendre le principe pour l’adapter à ses besoins.

PBonjour à tous,
Je vais enfin avoir le temps de me repencher sur la question.
Merci pour vos réponses. La dernière de @Draken me met devant mes lacunes en tant que débutant: je n’ai pas compris à quoi sert le init{
}
Quand on suit le cours de @mbritto certaines options sont abordées mais on n’a pas forcément le détail ou l’explocation Théorique de la notion.
Pour la logique de la démonstration, je pense que ça va et que je suis.

Maxime met un init dans ses manager mais pas dans la class. J’ai compris que c’etait Un constructeur. Donc, à priori, cela permet d’initialiser la construction d’un objet(?). Mais quand et pourquoi l’utiliser, pour l’instant, je n’ai pas compris.

Le init() permet de définir des paramètres lors de la création de la classe. J’aurais pu m’en passer, mais cela permet d’écrire un code très compact comme celui-ci :

tableau.append(Coureur(nom: "John", identifiant: 12))

C’est effectivement un constructeur pour reprendre la terminologie des langages objets. En déclarant une classe juste comme ça :

class Coureur {
        var nom = "nom"
        var identifiant = 0
    }

Swift génère automatiquement une fonction init (qui ne sera pas présente dans le code visible) se chargeant d’écrire nom dans la variable nom, et 0 dans identifiant.

Tu peux également avoir plusieurs init() pour créer ton objet de différentes manières.

    class Coureur {
        var nom = "nom"
        var identifiant = 0
        
        init(nom:String, identifiant:Int) {
            self.nom = nom
            self.identifiant = identifiant
        }
        
        init(identifiant:Int) {
            self.nom = "un élève"
            self.identifiant = identifiant
        }
    }

A noter que si j’avais écris la classe pour moi, j’aurais utilisé des variables optionnelles, pour plus de sécurité. C’est plus propre que de pré-initialiser le nom et l’identifiant avec des valeurs plus ou moins bidons (genre identifiant = 0)

class Coureur {
    var nom:String?
    var identifiant:Int?
    
    init(nom:String, identifiant:Int) {
        self.nom = nom
        self.identifiant = identifiant
    }
    
}

Hello,

bon, je bloque toujours. En testant la solution de @Draken, ça me retourne à la fin avec un tableau vide :

  func creerListeIdentifiants(listeCoureurs:[Coureurs]) -> [String] {
    var listeIdentifiants = [String]()
    for coureur in listeCoureurs {
        listeIdentifiants.append(coureur.team)
    }
    print("numeros tableau", listeIdentifiants)
    return listeIdentifiants

Sur un playGround, effectivement, ça fonctionne mais dès que je teste sur mon projet, cela reste vide. Ça doit surement venir de la spécificité de Realm… Pour rappel voici ma classe:

  `class coureurs: Object {
@objc dynamic private var _name = “”
@objc dynamic private var _prenom = “”
@objc dynamic private var _number = “”
}
`

ensuite, j’ai suivi le cours de Maxime.

var name:String {
get {
return _name
}
set {
_name = newValue
try? realm?.commitWrite()
}
}

etc.

Quand tu as un problème il faut faire appel à l’instruction print, pour afficher les étapes intermédiaires du processus.

Ecris quelque chose comme :

  func creerListeIdentifiants(listeCoureurs:[Coureurs]) -> [String] {

   print ("*****")
   print ("listeCoureurs : ", listeCoureurs)
    var listeIdentifiants = [String]()
    for coureur in listeCoureurs {
        print ()
        print ("---"
        print ("coureur : ", coureur)
        let team = coureur.team
        print ("team : ", team)
        listeIdentifiants.append(coureur.team)
    }
    print ()
    print ("-------")
    print("numeros tableau", listeIdentifiants)
    return listeIdentifiants
}

(code non testé, écrit à l’arrache sans Xcode sous la main).

Et regarde ce qui s’affiche. Tu verras si la boucle s’effectue (un tableau vide est souvent le résultat d’une boucle qui ne tourne pas).

Les lignes vides et les ------- peuvent sembler inutiles, mais permettent de se repérer quand l’affichage fait quelques centaines de lignes de long …

Si possible, réalise le test sur une petite quantité de données, une dizaine de coureurs par exemple.