J'ai donc une entité dans Core Data, appelons-la Parent définie comme :

extension Parent {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Parent> {
        return NSFetchRequest<Timer>(entityName: "Parent")
    }

    @NSManaged public var id: UUID
    @NSManaged public var children: Children
}

Et il a des enfants

public class Children: NSObject, NSCoding, ObservableObject {
    @Published var children: [Child]

    init(children: [Child] = [Child]()) {
        self.cycles = cycles
    }

    // code for encoding/decoding ...
}

Et child a une définition d'une collection de UUID/Strings/Int et est une structure

Ainsi, initialement, les parents sont affichés dans une vue de liste. Pour insérer un nouveau parent, vous appuyez sur un bouton plus, un nouveau parent est créé et persiste.

Il existe une autre vue pour ajouter des enfants au parent

Donc quel est le problème? Chaque fois qu'un nouveau parent est créé, il rend le contexte sale et context.hasChanges() renvoie true et le contexte peut être enregistré pour la persistance

Chaque fois que les enfants sont mis à jour, le contexte n'est pas sali et context.hasChanges() renvoie false, donc les mises à jour ne sont pas enregistrées

Je pense que le problème est dû au fait que les classes sont des types de référence, il ne semble pas que Parent ait changé car l'objet enfants est le même - mais les données qu'il contient ont changé. Alors, comment puis-je enregistrer les modifications ?

À moins de supprimer le parent et de le refaire lorsque des changements se produisent ou de mettre à jour une dernière variable mise à jour dans le parent, je ne vois pas comment j'obtiens le contexte pour réaliser qu'il y a des changements

1
Ilyas 10 oct. 2020 à 12:17

1 réponse

Meilleure réponse

Tldr : n'utilisez pas de propriétés transformables pour gérer les relations dans CoreData , utilisez des relations réelles.

Votre CoreData n'est pas marqué "sale" car votre propriété children est essentiellement un blob de Data qui encode/décode à la volée. Aucune notification de changement n'est générée lorsque vous mettez à jour vos enfants.

Alors que vous pourriez corriger la situation actuelle avec une implémentation comme celle-ci :

extension Parent {

    func addChild(_ child: Child) {
        willChangeValue(forKey: #keyPath(children))
        let childrenContainer = children as? Children ?? Children()
        childrenContainer.children.append(child)
        self.children = childrenContainer
        didChangeValue(forKey: #keyPath(children))
    }

}

Généralement, vous ne modéliseriez pas une relation parent/enfant comme celle-ci dans CoreData car elle est environ 6 à 10 fois plus lente qu'une relation réelle et ce n'est pas comment utiliser ce que fait CoreData.

Ce que vous voulez probablement, c'est une relation un-à-plusieurs

enter image description here

Ce qui se manifestera dans votre code comme

@NSManaged public var children: NSSet?

Vous pouvez également utiliser un NSOrderedSet (observez la case à cocher ordered sous le type de relation ).

La façon dont vous utilisez le Delete Rule dépendra de la façon dont vous souhaitez modéliser vos données. Nullify laissera les enfants orphelins sur la suppression par le parent, tandis que Cascade supprimera tous les enfants sur la suppression par le parent.

1
Warren Burton 10 oct. 2020 à 12:06