Bonjour
je suis le cours Créer des apps iPhone avec SwiftUI (Edition 2021 pour iOS 15) et dans le chapitre « Récupérer la liste des tâches sauvegardées », à 6’ 19" du début de la vidéo, je reproduit une situation identique sur mon éditeur et je n’arrive pas a supprimer l’erreur :
Pourtant la classe Bateau est construite comme la classe Task du tuto:
import Foundation
struct Bateau : Identifiable {
var id = UUID()
let nom : String
let longueur : Double
let largeur : Double
Mes problèmes sont ils dûs à la version 13.12.1 de xCode ou au à celle de swiftUI ou CoreData ?
Si quelqu’un peu me mettre sur la bonne piste?
Merci d’avance
Bonjour,
Une possible explication, si mes souvenirs sont bons:
-
CoreData ne peut jamais te garantir qu’un enregistrement n’est pas corrompu
-
Quand tu interroges un objet CoreData, tu peux obtenir nil même si la valeur n’est jamais censée être nil
-
C’est bien ce que tu fais en faisant un « unwrap » de coreDataObject.id, il faut donc que tu écrives self.id = id et self.nom = nom
Cordialement,
Nicolas
Merci Nicolas
je ne comprend pas bien.
self.id = id et self.nom = nom
ne fonctionne pas et d’ailleurs les autres champs de la table, qui ne sont pas obligatoires, ne provoquent pas d’erreur.
On dirai que le guard qui est sensé interdire que id et nom soient nuls, n’empêche pas le warning.
Pour info, il n’y a pour l’instant aucune donnée dans CoreData.
Je continue à chercher, merci
C’est à dire ? Peux-tu poster le code et le message d’erreur ?
Nicolas
Essaye
guard let objectId = coreDataObject.id, let objectName = coreDataObject.nom else {
return nil
}
self.id = objectId
self.nom = objectName
etc...
Et sinon, après un test fait sur Playground, reconstruis ton projet, ou quitte Xcode et redémarre
Meme erreur : Variable ‹ self.type › used before being initialized
Je redémarre xCode, mais je l’ai déjà fait …
Je teste ça dans SwiftPlayground, qui compile sans problème…
struct Bateau: Identifiable {
var id = UUID()
let nom:String
}
struct ProxyCoreDataBateau {
let id: UUID?
let nom: String?
}
extension Bateau {
init?(fromObject proxyObject:ProxyCoreDataBateau) {
guard let id = proxyObject.id, let nom = proxyObject.nom else { return nil}
self.id = id
self.nom = nom
}
}
Ok donc on met cela
import Foundation
import CoreData
import UIKit
class CoreDataStorage{
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Bateau")
container.loadPersistentStores { description, error in
if let error = error {
fatalError("Unable to load persistent stores: \(error)")
}
}
return container
}()
var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
func fetchBateauList() -> [Bateau] {
let bateauList:[Bateau]
let fetchRequest:NSFetchRequest<CDBateau> = CDBateau.fetchRequest()
if let rawBateauList = try? context.fetch(fetchRequest){
bateauList = rawBateauList.compactMap({(rawBateau:CDBateau) ->
Bateau? in
Bateau(fromCoreDataObject: rawBateau)
})
} else {
bateauList = []
}
return bateauList
}
func addBateau(bateau:Bateau) {
let newBateau = CDBateau(context: context)
newBateau.id = bateau.id
newBateau.nom = bateau.nom
newBateau.longueur = bateau.longueur
newBateau.largeur = bateau.largeur
newBateau.tirantdeau = bateau.tirantdeau
newBateau.tirant_dair = bateau.tirant_dair
newBateau.constructeur = bateau.constructeur
newBateau.modele = bateau.modele
newBateau.annee_construction = Int64(bateau.annee_construction)
newBateau.fuel = Int64(bateau.fuel)
newBateau.eau = Int64(bateau.eau)
saveData()
}
private func saveData(){
if context.hasChanges {
do {
try context.save()
} catch {
print("Erreur pendant la sauvegarge CoreData : \(error.localizedDescription)")
}
}
}
}
extension Bateau {
init?(fromCoreDataObject coreDataObject:CDBateau){
guard let id = coreDataObject.id,
let nom = coreDataObject.nom else
{
return nil
}
self.id = id
self.nom = nom
self.longueur = coreDataObject.longueur
self.largeur = coreDataObject.largeur
self.tirantdeau = coreDataObject.tirantdeau
self.tirant_dair = coreDataObject.tirant_dair
self.constructeur = coreDataObject.constructeur!
self.modele = coreDataObject.modele!
self.annee_construction = Int(coreDataObject.annee_construction)
self.fuel = Int(coreDataObject.fuel)
self.eau = Int(coreDataObject.eau)
}
}
ce qui génère une seule erreur à la fin
On est bien d’accord que pour les autres champs on maintient coreDataObject.
le Variable ‹ self.type › used before being initialized semble indiquer qu’on de fait pas les choses dans le bon ordre, peut-être à cause de l’extension?
Je vais continuer à fouiner…
Essaye de supprimer les autres lignes, ou de les remplacer par qq chose comme self.longueur = 3.0
En fait le tuto a été fait avec les 2 champs obligatoires dans la table: id et name, mais les autres champs sont à intégrer aussi…
Je suis débutant sur swift donc je suis un peu perdu.
Je vais laisser tout cela en pause car il y a 2 jours que je tourne en rond avec ce problème que je ne suis pas encore en état de dominer. Cela me laisse un peu songeur de voir qu’une simple relation entre une entité et la base de donnée qui va la mémoriser soit si difficile à mettre en place à cause d’un langage hyper strict.
Merci pour ton aide
Cordialement.
Essaye de déclarer longueur, etc… en var et non en let dans Bateau
Bonsoir,
Je viens de faire le même type de test dans Xcode, et j’obtiens l’alerte Variable ‹ self.xxx › used before being initialized si xxx n’est pas initialisé dans la fonction init.
Vérifie donc que TOUTES les constantes et variables de Bateau sont bien initialisées dans ta fonction init.
Dit autrement, pour la variable « longueur »:
- si tu ne déclares pas self.longueur dans le init(), tu auras cette erreur
- si tu déclares self.longueur = 3.0 et que tu fais de même pour toutes les constantes et variables de Bateau(*), le message pourrait disparaître
(*) ou plus exactement les constantes et variables qui n’ont pas une valeur par défaut
À suivre
Nicolas
Le code suivant compile sur Xcode 13.2.1 chez moi:
import Foundation
struct Bateau: Identifiable {
var id = UUID()
let nom:String
let longueur: Double
let largeur: Double
}
struct ProxyCoreDataBateau {
let id: UUID?
let nom: String?
let longueur: Double
let largeur: Double?
}
extension Bateau {
init?(fromObject proxyObject:ProxyCoreDataBateau) {
guard let id = proxyObject.id, let nom = proxyObject.nom else { return nil}
self.id = id
self.nom = nom
longueur = proxyObject.longueur
largeur = proxyObject.largeur ?? 0.0
}
}
Si je supprime l’une des deux lignes « longueur = … » ou « largeur = … », j’ai droit à l’erreur
Nicolas
Bravo Nicolas,
c’était bien une faute d’inattention: variable manquante.
Ça compile bien!
Désolé de t’avoir donné tant de mal, mais pas inutilement puisque apparement il fallait bien enlever le coreDataObject. sur les 2 premieres lignes id et nom, contrairement à ce qui est fait dans le tuto (Peut-être l’effet des dernières versions de SwiftUI).
Merci encore, je vais pouvoir continuer dans mon apprentissage.
Merci @Holliver , content que le problème soit réglé !