[Résolu] "Magie" Core Data: encore une explication souhaitée
Bonjour,
Il n'y a rien de magique dans Core Data, nous sommes d'accord, mais là j'ai un truc qui fonctionne alors qu'il ne devrait pas (en principe) et j'aimerais savoir pourquoi.
Je sous-classe souvent des NSArrayControllers, et maintenant je fais pire: je sous-classe mes propres NSArrayControllers...
Comme deux NSArrayControllers (qui gèrent des Entities différentes) ont pas mal de comportements similaires, j'ai décidé de créer une classe abstraite BasicController dont héritent PlaceController (entité Place) et ThingController (entité Thing). Les entités Place et Thing dérivent elles-mêmes d'une entité abstraite Basic, qui leur fournit des propriétés communes, dont un set d'erreurs.
Ces deux contrôleurs sont instanciés par IB et ont les outlets sur le managedObjectContext du document. BasicController ne l'est pas (puisqu'il est abstrait).
A un moment donné, j'ajoute une erreur à l'une des deux entités via son contrôleur, qui appelle la méthode de BasicController. Elle fait ceci:
- (IBAction)addError:(id)sender
{
Error *error = [NSEntityDescription insertNewObjectForEntityForName:@Error inManagedObjectContext:self.managedObjectContext];
Basic *basic = self.selectedObjects.lastObject;
[basic addErrorsObject:error];
[self rearrangeObjects];
}
... et ça marche.
Mais comment? Je sais que NSArrayController hérite de NSObjectController, qui possède la propriété managedObjectContext, mais par quel miracle (peut-être dangereux) BasicController connaà®t-il le bon contexte? C'est sûrement documenté quelque part, mais je précise que BasicController n'apparaà®t pas dans IB, qu'il n'a aucun outlet sur le document, que je ne l'initialise même pas...
Vous avez une explication?
Réponses
Heu bah c'est de l'héritage là hein...
Ton PlaceController a été réglé dans IB avec le bon managedObjectContext. Donc quand les méthodes hérités l'utilisent, bah elles y ont accès...
Au passage, mauvaise pratique de sous classer NSArrayController. Trop opaque comme objet pour que ce soit updateproof.
Salut yoann,
Mais là c'est pas de l'héritage... les deux contrôleurs n'implémentent pas la méthode addError, c'est la méthode générique qui est appelée. Un peu comme si la classe parente héritait d'une propriété d'une classe fille. Je ne dois pas être à mon affaire.
Attention, je ne bidouille pas dans NSArrayController, je rajoute des méthodes, comme on le ferait à une NSView. Par exemple, l'arrayController est chargé de vérifier la cohérence de certaines propriétés de son contenu, il est pratique (via ses arrangedObjects) de le faire directement. Si les contrôleurs ne peuvent pas jouer leur rôle d'intermédiaire entre le modèle et la tableView, qui va le faire?
Ce n'est pas la première fois que je vois cette remarque, cependant. Mais Hillegass lui-même le fait dans un de ses exemples assez basiques, et je ne vois pas le risque. Ce n'est pas comme si j'allais bidouiller dans un cluster comme NSDictionary...
Pourtant dans ton premier post :
Donc tu es bien dans une relation d'héritage. Je ne comprends pas ton soucis.
Quelle garantie tu as qu'à l'avenir Apple ne rajoute pas une méthode au nom identique ? Aucune.
NSArrayController n'est pas franchement prévu pour être étendu contrairement à NSObject ou NSView.
Je n'avais pas les yeux en face des trous je pense. Le self.managedObjectContext est lui aussi hérité, et donc fixé par la classe fille.
Alors ça c'est valable pour toutes les classes. C'est pourquoi il faudrait préfixer jusqu'aux méthodes... ou alors choisir le français mais j'ai toujours trouvé moche de mélanger les langages comme if (monPortemonnaie isEqualTo ensembleVide)...
yoann si tu retrouves la documentation officielle qui indique que pour NSArrayController c'est effectivement à ne pas faire, je suis intéressé. Car sinon, comme Berfis, je ne vois pas trop en quoi NSArrayController ferait exception par rapport aux autres ?
NSArrayController est ouvert à la sous-classe, c'est spécifié dans la documentation d'Apple.
Ce n'est pas pour autant que ce n'est pas une mauvaise idée.
C'est une classe liée à CoreData, qui propose un fonctionnement complexe, qui est assez peu documenté. Son unique rôle est de simplifier le fonctionnement de CoreData.
N'importe quel développeur OS X avec un minimum d'expérience te dira que c'est une assez mauvaise idée de le sous-classer, l'encapsuler est bien plus sage vis à vis des blagues habituelles d'Apple et plus propre en terme de conception.
Par exemple, j'ai déjà eu des NSArrayController sur OS X qui ne se comportaient pas de la même manière selon s'ils étaient encapsulé dans un NSObject ou un NSViewController.
NSArrayController est un objet beaucoup trop opaque pour être sous classé avec confiance.
Pour ma part vis à vis de la doc d'Apple je considère trois scénario pour pas avoir d'emmerde :
Je partage totalement l'avis de yoann.
Je le déconseille systématiquement pour les mêmes raisons (classe qui fait trop de chose, mal documentée). C'est toujours une mauvaise idée de sous-classer une classe dont on comprend mal le fonctionnement. Je m'y suis cassé les dents, parce que j'ai surchargé une méthode qui était appelée par une autre en interne, et ça faisait n'importe quoi.
Je préfère instancier une sous-classe de NSObject dans mon xib, dans lequel je crée les actions. Je peux créer une outlet sur le NSArrayController, si besoin. Je n'y vois aucune limitation.