CoreData : awakeFromInsert

cargocargo Membre
07:44 modifié dans API AppKit #1
awakeFromInsert est une fonction appelée automatiquement par la managedObjectContext au moment de l'insertion d'une nouvelle instance d'une Entity, d'un nouveau managedObject.

awakeFromInsert n'est appelée q'une seule fois au cours du life-cycle d'un objet, au moment de sa création uniquement, alors que initWithEntity:insertIntoManagedObjectContext: sera appelé à  chaque fois que l'objet est récupéré dans le persistentStore (ouverture du document par exemple)

awakefromInsert est donc bien utile pour attribuer une date de création ou une id unique à  un objet ; mais qu'en est-il si, comme moi, on souhaite l'utiliser pour attribuer une valeur calculée à  un objet B, ce calcul dépendant d'une valeur située à  l'autre bout d'une relationship de l'objet B ?

Le but : stocker une valeur calculée une fois pour toutes lors de la création de l'objet B, pour qu'elle ne soit plus jamais mise à  jour par la suite même si la valeur de l'objet A lié dont elle dépend change.
A<--->>B
Au fil du temps chaque objet B aura sa propre valeur calculé à  partir de A au moment de sa création. Les valeurs dans B reflèteront alors les variations de la valeur de A au cours du temps.

Le problème : au moment de awakeFromInsert, l'instance n'est pas encore "consiente" de ses relationships dans le managedObjectContext (contrairement à  awakeFromFetch)

Une solution ?
Dans l'example iClass de Xcode, il y a un IDgenerator, entity qui n'a aucune relation d'aucun genre, avec aucune autre entity, dans le managedObjectModel. IDgenerator a un attribute où sont stockées les valeurs des Id's et un attribute ou plutôt une fonction qui renvoie un nombre (elle n'apparait pas dans le mom à  cause d'un problème de validation loop).
<br />@implementation IDGenerator<br />// This is unmodeled, because otherwise we get caught in a validation loop before saving<br />// since accessing the property during validation would cause it to change<br />- (NSNumber *)getNewID {<br />&nbsp; &nbsp; NSNumber *tempCurrent = [self primitiveValueForKey: @&quot;mostRecentID&quot;];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; if (nil == tempCurrent) {<br />&nbsp; &nbsp; &nbsp; &nbsp; tempCurrent = [NSNumber numberWithInt: 100000];<br />&nbsp; &nbsp; &nbsp; &nbsp; [self willChangeValueForKey: @&quot;mostRecentID&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; [self setPrimitiveValue: tempCurrent forKey: @&quot;mostRecentID&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; [self didChangeValueForKey: @&quot;mostRecentID&quot;];<br />&nbsp; &nbsp; } else {<br />&nbsp; &nbsp; &nbsp; &nbsp; tempCurrent = [NSNumber numberWithInt: ([tempCurrent intValue] + 1)];<br />&nbsp; &nbsp; &nbsp; &nbsp; [self willChangeValueForKey: @&quot;mostRecentID&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; [self setPrimitiveValue: tempCurrent forKey: @&quot;mostRecentID&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; [self didChangeValueForKey: @&quot;mostRecentID&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return tempCurrent;<br />}<br /><br />@end<br />


>>> voilà  comment Person.m récupère l'id au moment d'awakeFromInsert, c'est le chemin utilisé qui me parait intéressant :
<br />- (void)awakeFromInsert {<br /> [self setPrimitiveValue: [[[[NSApplication sharedApplication] delegate] idGenerator] getNewID] forKey: @&quot;personID&quot;];<br />}<br />


>>> l'implémentation du delegate (ce n'est pas une appli NSPersistentDocument)
<br />/////// A quoi sert cette fonction ???? :<br /><br /><br />@implementation iClassAppDelegate<br />- (IDGenerator *)idGenerator {<br />&nbsp; &nbsp; return idGenerator;<br />}<br /><br /><br /><br />//// Ca je suppose que c&#39;est uniquement pour gérer le fait qu&#39;il y a 2 persistent stores ??? :<br /><br /><br />- (void)getOrCreateIDGeneratorInStore: (id)store {<br />&nbsp; &nbsp; NSFetchRequest *request = [[self managedObjectModel] fetchRequestTemplateForName: @&quot;generators&quot;];<br />&nbsp; &nbsp; [request setAffectedStores: [NSArray arrayWithObject: store]];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSError *error = nil;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSArray *generators = [[self managedObjectContext] executeFetchRequest: request error: &amp;error];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; if (nil == error) {<br />&nbsp; &nbsp; &nbsp; &nbsp; if (0 == [generators count]) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idGenerator = [[IDGenerator alloc] initWithEntity: [[managedObjectModel entitiesByName] valueForKey: @&quot;IDGenerator&quot;] insertIntoManagedObjectContext: managedObjectContext];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [managedObjectContext assignObject: idGenerator toPersistentStore: store];<br />&nbsp; &nbsp; &nbsp; &nbsp; } else {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idGenerator = [[generators objectAtIndex: 0] retain];<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; } else {<br />&nbsp; &nbsp; &nbsp; &nbsp; [[NSApplication sharedApplication] presentError:error];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return;<br />}<br /><br /><br />@end<br />



Où est-ce que j'en suis ?

Avec le sinueux chemin suivant (après setValue) : j'appelle le moc car l'objet B est conscient du moc au moment de awakeFromInsert, je parcours modèle et entités et  j'arrive enfin à  ma class A pour lui demander à  ce que ma_Méthode me renvoie quelque chose. Mais ma_Méthode est forcément ici, avec ce chemin, une méthode de classe (actuellement elle renvoie une constante).
<br />- (void)awakeFromInsert<br />{<br />[super awakeFromInsert];<br />[self setValue:&nbsp; &nbsp;  [&nbsp;  [[NSBundle mainBundle] classNamed:[[[[[[self managedObjectContext] persistentStoreCoordinator] managedObjectModel] entitiesByName] objectForKey: @&quot;Entité_A&quot;] managedObjectClassName]&nbsp; ]&nbsp; &nbsp; &nbsp;  ma_Méthode ]&nbsp; &nbsp; &nbsp; &nbsp;  forKey:@&quot;attribut_De_B&quot;];<br />}<br />


voilà  ma_Méthode :

<br />+(NSNumber*)ma_Méthode<br />{<br />	return [NSNumber numberWithDouble: 543 ]; <br />}<br />



Mes questions:
> Est-ce qu'il y a un moyen pour que ma méthode de classe me renvoie la valeur d'un attribut d'une de ses instances par exemple me renvoie valueForKey:@Attribut_ A de l'objet selectionné dans une tableView ou un pop-up, ou éventuellement à  partir de l'objectId. ?
> Est-ce qu'une méthode de classe ne peut pas renvoyer l'éxecution d'une méthode d'instance (du genre "ok message reçu, je run ma méthode d'instance et le controller se débrouillera pour trouver à  quel instance elle s'applique")
> Est-ce qu'il n'y a pas une autre chemin pour atteindre une méthode d'instance, et dans ce cas, est ce que la méthode d'instance va me renvoyer la valueForKey de l'objet selectionné dans la tableView (je suppose que oui, ça c'est le boulot du controller) ?

Ps1 : toute autre suggestion est la bienvenue... :)
Ps2 : je poste ici si je trouve une solution.




Réponses

  • mars 2006 modifié #2
    dans 1141991747:

    Ps1 : toute autre suggestion est la bienvenue... :)


    - Dire la finalité de ce que tu veux faire (genre j'ai une base de donnée de produits, je voudrais que la première partie du numéro de référence d'un produit soit lié au groupe auquel il appartient, et la seconde partie est son identifiant au sein de la catégorie), ça évitera de se prendre la tête à  imaginer des réalisations concrètes de ce que tu veux faire. Des trucs genre A, B, attribut_de_B c'est tout sauf parlant.
    - formuler des questions plus courtes: n'oublie pas que la plupart de ceux qui répondent font ça pendant leur pause café (ou pendant que ça compile...) et sur cette base ils ne répondront pas à  la question s'il leur faut la durée de la pause café pour lire - et comprendre - la question.
    - ne pas hésiter à  créer un sujet par question.

    Bon ce n'est sans doute pas le type de réponse que tu voulais.
Connectez-vous ou Inscrivez-vous pour répondre.