Core Data: accès aux données...

ersers Membre
00:59 modifié dans API AppKit #1
Bonjour,

J'ai fait une petite application avec une NSTableView et qui utilise CoreData pour gérer les données dans la table. Rien de très sorcier, j'ai fait un quasi copier-coller de sources d'exemples qu'on trouve un peu partout sur le net, et ô joie, ça fonctionne.

Pas (du tout) spécialiste de CoreData que je suis, pour accéder aux données de la table ensuite dans mon programme j'ai fais la chose suivante:
NSArray *array = [myArrayController content];


Peut-être qu'il y a une autre façon d'accéder aux données plus rapidement, simplement, ou proprement, et je serais ravi qu'on m'en apprenne plus si c'est le cas...

Bon, donc ça marche mais il y a un soucis: la NSTableView doit impérativement avoir été affichée au moins une fois avant l'appel à  la méthode "content", sinon celle-ci me renvois des lignes avec marqué:
<NSManagedObject: 0x3d8430> (entity: Record; id: 0x370220 <x-coredata://3B86B212-74C9-47D4-A6BC-AF3BDB393174/Record/p120> ; data: <fault>


J'ai "<fault>" au lieu du contenu normal de mes valeurs. J'en déduit donc que CoreData ne charge réellement les données qu'à  partir du moment où la table le lui a demandé.
C'est fâcheux car j'aurais besoin d'accéder aux données même si l'utilisateur n'a pas eu envie d'ouvrir l'onglet où est rangée la tableview.

J'ai cherché un peu un moyen de forcer ce chargement, et j'ai trouvé un truc qui va je crois me faire aller tout droit au bûcher si je vous le montre, mais tant pis, allons-y:  :brule:

<br />[[myArrayController] newObject];<br />[[myArrayController managedObjectContext] rollback];<br />NSLog (@&quot;%@&quot;, [[myArrayController] content]);<br />


Et là  après cette bidouille "content" me donne ce que je veux dans le log...

Donc si vous avez mieux je prends de suite ! :why?:

D'avance merci,
Eric

Réponses

  • Philippe49Philippe49 Membre
    00:59 modifié #2
    Utiliser NSFetchRequest sur le managedObjectContext.
  • CéroceCéroce Membre, Modérateur
    00:59 modifié #3
    On en revient au paradigme MVC.
    Il ne faut pas que tu ailles chercher les données dans le NSArrayController (couche contrôleur), mais bien dans la couche modèle (le Managed Object Context, comme indiqué par Philippe). Le MOC n'est rien d'autre qu'une base de données, sur laquelle tu vas lancer des requêtes.

    Le code présenté ajoute une catégorie au Managed Object Context, mais tu peux t'en inspirer:
    http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html

  • ersers Membre
    00:59 modifié #4
    Bonjour à  vous deux, et merci de m'avoir répondu...

    Alors j'ai essayé la chose suivante à  partir du code trouvé par Céroce:
    NSEntityDescription *entity;<br />NSError *error = nil;<br />NSFetchRequest *request;<br />NSManagedObjectContext *context;<br />NSPredicate *predicate;<br />NSSortDescriptor *descriptor;<br /><br />context = [myArrayController managedObjectContext];<br />entity = [NSEntityDescription entityForName:@&quot;Record&quot; inManagedObjectContext:context];<br />request = [[NSFetchRequest alloc] init];<br />[request setEntity:entity];<br />predicate = [NSPredicate predicateWithFormat:@&quot;PTEC = FALSE&quot;];<br />[request setPredicate:predicate];<br />descriptor = [[NSSortDescriptor alloc] initWithKey:@&quot;date&quot; ascending:YES selector:@selector (compare:)];<br />[request setSortDescriptors:[NSArray arrayWithObject:descriptor]];<br /><br />NSLog (@&quot;valeurs: %@&quot;, [context executeFetchRequest:request error:&amp;error]);<br /><br />[descriptor release];<br />[request release];
    


    Bon, alors déjà  ça fonctionne... mais... c'est encore une fois le même problème qu'avant: il faut que la tableView ai été affichée au moins une fois avant l'appel de ce code sinon je reçoit que des:
    &lt;NSManagedObject: 0x3dcb60&gt; (entity: Record; id: 0x365190 &lt;x-coredata://3B86B212-74C9-47D4-A6BC-AF3BDB393174/Record/p131&gt; ; data: &lt;fault&gt;)
    

    Ce qui m'arrange pas trop, et c'était pareil que quand je faisais juste:
    NSArray *array = [myArrayController content];
    


    :'(

    C'est donc pas la récupération des données qui me semble foireuse, mais plutôt qu'il faudrait "forcer" les données à  être chargées (ce qui n'est à  mon avis pas fait vu le "fault").

    a+
    Eric
  • ersers Membre
    00:59 modifié #5
    Une question supplémentaire...

    Pour ajouter, par programmation, des données dans ma table je fais:

    object = [baseArrayController newObject];<br />[object setValue:(NSDate *)date forKey:@&quot;date&quot;];<br />...<br />[baseArrayController addObject:object];<br />[object release];<br />
    


    ça a l'air de fonctionner, c'est la bonne façon de s'y prendre ?

    Et pour effacer (dans cet exemple, ceux qui ont plus de 7 jours):

    values = [baseArrayController content];<br />valuesToDelete = [NSMutableArray arrayWithCapacity:[values count]];<br />enumList = [values objectEnumerator];<br />while (object = [enumList nextObject])<br />{<br />	if ([date timeIntervalSinceDate:[object valueForKey:@&quot;date&quot;]] &gt; 7*24*60*60)	// 7 jours<br />		[valuesToDelete addObject:object];<br />	else<br />		break;<br />};<br />[baseArrayController removeObjects:valuesToDelete];
    


    Là  par contre je crois que vu ce que vous m'aviez dit, je pourrais employer "executeFetchRequest" pour trouver les fichiers à  effacer. ça devrait peut-être plus rapide que de lister un par un les objets comme je le fais actuellement.
    Mais je ne vois pas trop la syntaxe du filtre à  employer pour faire cela avec le NSPredicate.
  • Philippe49Philippe49 Membre
    00:59 modifié #6
    dans 1244889771:

    Une question supplémentaire...

    Pour ajouter, par programmation, des données dans ma table je fais:

    object = [baseArrayController newObject];<br />[object setValue:(NSDate *)date forKey:@&quot;date&quot;];<br />...<br />[baseArrayController addObject:object];<br />[object release];<br />
    



    Ce n'est pas ainsi que le recommande la doc de CoreData (confère la remarque de Céroce sur le model MVC)
  • ersers Membre
    00:59 modifié #7
    Bonjour à  tous,

    Alors je me suis pris un peu la tête avec tout ça, mais finalement pour la création d'objets j'ai fait ainsi:
    context = [baseArrayController managedObjectContext];<br />newRecord = [NSEntityDescription insertNewObjectForEntityForName:@&quot;Record&quot; inManagedObjectContext:context];<br />[newRecord setValue:(NSDate *)date forKey:@&quot;date&quot;];<br />...<br />[context save:&amp;error];<br />
    


    ça me créé bien un nouvel objet et le "save:" actualise la tableView. Bien !

    Par contre pour mon histoire de "fault", j'ai cherché dans la doc d'Apple et j'ai trouvé ce chapitre:

    http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdUsingMOs.html#//apple_ref/doc/uid/TP40001803-SW8

    Il semblerait que ça soit parfaitement normal et si on fait "valueForKey:" sur un des objets, la valeur est belle et bien trouvée ! CoreData n'a l'air de charger les données en fait que si on utilise les clés, et pas forcément quand on fait un bête NSLog sur les objets !

    Je commence un peu à  comprendre tout ça (joie) et à  me rendre compte que j'étais pas très malin. :o

    ps: et pour le filtre predicate j'ai fait ça:
    predicate = [NSPredicate predicateWithFormat:@&quot;date &lt; %@&quot;, [[NSCalendarDate calendarDate] dateByAddingYears:0 months:0 days:-7 hours:0 minutes:0 seconds:0]];
    
  • Philippe49Philippe49 Membre
    00:59 modifié #8
    dans 1245001390:

    Bonjour à  tous,

    Alors je me suis pris un peu la tête avec tout ça, mais finalement pour la création d'objets j'ai fait ainsi:
    context = [baseArrayController managedObjectContext];<br />newRecord = [NSEntityDescription insertNewObjectForEntityForName:@&quot;Record&quot; inManagedObjectContext:context];<br />[newRecord setValue:(NSDate *)date forKey:@&quot;date&quot;];<br />...<br />[context save:&amp;error];<br />
    



    Cela me semble plus conforme. CoreData nécessite de suivre très précisément les consignes de la doc, sinon tu as des bugs qui apparaissent dans le KVO pour le undo/redo par exemple.
  • ersers Membre
    00:59 modifié #9
    dans 1245051246:

    Cela me semble plus conforme. CoreData nécessite de suivre très précisément les consignes de la doc, sinon tu as des bugs qui apparaissent dans le KVO pour le undo/redo par exemple.


    Voilà  qui fait une excellente raison de passer par le managedObjectContext... Merci des conseils.
Connectez-vous ou Inscrivez-vous pour répondre.