Swift et sous classe de NSManagedObject
Kubernan
Membre
Bonjour,
Je suis en train de tester l'intégration de Swift à CoreData. D'abord en créant des sous classes de NSManagedObject.
Je suis déjà déconcerté à ce stade. Je m'explique.
Prenons une entité avec deux dates. Lorsque je mets à jour la première, la seconde est automatiquement mise à jour en fonction de la valeur de la première date.
Avec Objective-C j'utilisais cette méthode :
@dynamic timeStamp;
@dynamic date; // Date qui est calculee automatiquement selon la valeur de timeStamp
// Des que je fais appel au setter de "timeStamp" j'en profite pour calculer "date"
- (void)setTimeStamp:(NSDate *)timeStamp { // Setter
[self willChangeValueForKey:@date];
[self setPrimitiveTimeStamp:timeStamp];
self.date = // je bidouille une date avec timeStamp;
[self didChangeValueForKey:@date];
}
Avec Swift je n'ai pas trouvé le moyen de reproduire ce code. La seule chose qui fonctionne est ceci :
class Event : NSManagedObject {
@NSManaged var timeStamp: NSDate
@NSManaged var date: NSDate
init(entity: NSEntityDescription!, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
super.init(entity: entity, insertIntoManagedObjectContext: context)
addObserver(self, forKeyPath: "timeStamp", options: NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Old, context: nil)
}
override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: NSDictionary!, context: CMutableVoidPointer) {
if (keyPath == "timeStamp") {
updateDate()
}
}
func updateDate () {
willChangeValueForKey("date")
self.setPrimitiveValue(/*Je bidouille une date*/, forKey: "date")
didChangeValueForKey("date")
}
}
Utilisation de KVO donc. Bien que cela soit parfaitement valide, je trouve le code nettement plus obscure. J'ai tenté d'utiliser les setter à la façon de Swift ("set") mais c'est refusé par XCode.
Visiblement, pas d'autre moyen que de procéder ainsi.
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Genre (pas testé, code en live à adapter/corriger)
La doc Swift sur le sujet
J'avais déjà essayé... refusé également : "NSManaged not allowed on observing properties"
Moi pas encore, mais je me dis qu'ils parlent peut-être un peu de ce genre de choses, sait-on jamais ?
Pourquoi date n'est pas une propriété "transient" (et du coup non @NSManaged) ?
Puisqu'après tout, si ta NSDate est calculée d'après ton timestamp, tu n'as besoin que de stocker ton timestamp dans ton DataModel, et ta NSDate sera alors une "computed property", non ?
J'ai regardé... y a pas grand chose, et Melissa propose le même code que moi.
Mon exemple est simplifié. En réalité j'utilise deux dates dont une qui représente le mois (façon normalisé) de la première date. Je la stocke pour des raisons de performances lors de mes requêtes et de l'affichage dans les tables view.
Ah ah ah ! Ouais, à force de regarder toutes ses vidéos je me sens intime.
Je suis un peu surpris que tu aies pu le faire en ObjC à vrai dire. Faut mieux utiliser le KVO pour ces trucs là que surcharger un setter/getter d'une @property managée, à mon avis, car un objet managé ça doit pas être simple sous le capot (contexte lié tout ça).
Par contre c'est dommage que Swift ne te permette pas le willSet/didSet sur des @NSManaged, et que tu sois obligé de passer par le KVO d'ObjC, je suis surpris/déçu. Faudrait que t'envoies un mail ou un tweet à Melissa (ou à Chris) pour leur demander
Ceci dit il ne faut pas oublier que Swift est un langage encore jeune, et surtout encore en Beta. On sait déjà que dans la seed actuelle d'Xcode6 :
- Y'a des bugs avec Swift et les IBOutlets
- Il n'y a pas encore les access modifiers (private/public/...), même si ça va venir
Donc c'est possible qu'il y ait aussi des ratés sur @NSManaged.
N'hésite pas à remonter un bug via le BugReport (même si le mieux aurait été d'aller voir Mélissa ou Crhis directement lors de la WWDC, hein ? ) d'autant qu'ils sont preneurs de retours sur comment améliorer Swift d'ici la sortie " ils l'ont assez laissé entendre dans leurs vidéos je pense.
Avant de surcharger les setter j'ai fait pas mal de tests pour vérifier que je n'avais pas mis la grouille quelque part. Notamment et surtout les notifications de contexte.
Jusqu'à maintenant je n'ai jamais eu de soucis. Ce qui ne veut pas dire qu'il n'y en aurait pas, j'en conviens.
Comme toi, je trouve dommage cette histoire d'observer à la swift qui n'est pas autorisé pour les NSManagedObject.
Oui, je vais écrire à Melissa, comme j'ai écrit à Tim pour Aperture... mais c'est une autre histoire :-)
Merci de ton aide.
Dernière chose. Pour que le runtime prenne en compte les sous-classe de NSManagedObject en swift il faut utiliser une nouvelle syntaxe dans le champ Class de l'éditeur du modèle : NomAppli.NomSousClasse (en ObjC on ne met que le nom de la sous-classe).