NSTableView et Core Data

Bonsoir,


 


Auriez-vous un tutoriel pour afficher des données coredata dans une NSTableView crée sur un XIB car j'ai essayé plusieurs tutoriel trouvé sur google mais à  chaque fois rien ne s'affiche.


 


Merci d'avance...


«1

Réponses

  • berfisberfis Membre
    décembre 2013 modifié #2

    Bonsoir aurel,


     


    L'incontournable ouvrage de Aaron Hillegass (rien que pour le look du bonhomme, déjà ) donne de bons exemples pour un début!


     


    Pour faire plus court et t'épargner (provisoirement) la dépense, tu peux poster ton projet qu'on voie ce qui manque...


  • Quel est le soucis exactement ?


     

    - Maà®trises-tu la population de données (même fixes et créées à  la main) d'une NSTableView ?


    - Maà®trises-tu la récupération de données d'un CoreData (via certains critères/NSPredicate) ?


     


    En fonction, on sera plus à  même de t'aider, car là , c'est vague. On ne sait même pas si ça compile, si ce sont de mauvaises données qui sont affichées, si rien ne s'affiche, s'il les données récupérées dans ta BdD sont mauvaises, etc.


  • Je pense que ce serait plus simple qu'il poste le projet, Larme, parce que cela répondrait à  beaucoup de questions d'un coup...


  • Vous voulez un zip du projet pour encore mieux voir?


  • Oui, tu peux joindre un zip du projet, ça vaut mieux qu'un long discours, le temps que l'autre comprenne ce que tu veux en général tu trouves toi-même  :)


  • Voilà  le zip si tu as besoin d'info j'suis là   :D


  • berfisberfis Membre
    décembre 2013 modifié #8

    Premières remarques:


    1. Où sont tes contrôleurs ?


    2. Pourquoi générer des classes à  partir de tes entités Core Data si tu ne modifies pas leur comportement?


    3. Pourquoi t'échiner à  une dériver une sidebar de NSView dans le seul but de lui donner une couleur de fond alors que la classe d'origine le fait? Et surtout, pourquoi une NSView? C'est une NSTableView qu'il te faut...


    4. Pourquoi :



    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
    [prefWindow setIsVisible:NO];
    [aboutPanel setIsVisible:NO];
    [addContactWindow setIsVisible:NO];
    [viewContactWindow setIsVisible:NO];
    [addEntrepriseWindow setIsVisible:NO];
    ...

    alors qu'il suffit de décocher la case "Visible at launch" dans IB?


     


    Sinon, du peu que j'en ai vu, ta "table" n'affiche rien parce que


    a- ce n'est pas une table


    b- il n'existe aucune connection entre ton modèle Core Data et tes vues (pas de contrôleurs, pas de bindings, pas de datasource, pas de target-actions)...


     


    Notre expert en documentation (AliGator-la-doc-c'est-moi) pourrait te répondre bien mieux que moi, mais je te conseille tout de même:


     


    https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/Model-View-Controller/Model-View-Controller.html


    https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html


    https://developer.apple.com/library/ios/documentation/DataManagement/Devpedia-CoreData/coreDataOverview.html


     


    Pars d'un tutoriel bien fait, hyper-simple, et complexifie ensuite. Ton appli fait appel à  des notions qui ne sont pas évidentes à  mettre en place et à  relier les unes aux autres.


     


    Courage et bonne lecture!


  • aurelaurel Membre
    décembre 2013 modifié #9

    J'ai tout supprimé et je reprend à  zéro.


     


    Et tu connais un tutoriel simple sur google?


  • Google Is Your Friend:


    http://themikeswan.wordpress.com/2009/05/22/7/


     


    Mais tu ne couperas pas à  la lecture des manuels.


     


    Et dis-toi que si tu obtiens des résultats assez vite, c'est que Core Data a un petit côté jésuite (venez à  moi, c'est tout simple) mais que tu vas te cogner encore souvent la tête contre les murs si tu batifoles du côté des NSOutlineViews, NSTreeControllers et view-based NSTableViews.


     


    Je le sais, j'ai encore les bosses.


     


    Courage et tiens-nous au courant !


  • Maintenant quand je build j'ai le message "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store." qui apparait en alerte.


     


    Pourtant j'ai suivis le tutoriel que tu m'as donné.


  • AliGatorAliGator Membre, Modérateur
    Bah oui ça se comprend il a créé un persistant store avec un modèle objet (ensemble de classes / entités / relations) donné, puis tu as certainement dû totalement le modifier depuis (sans doute as-tu supprimer un bon nombre voire toutes tes entités de ton modèle CoreData pour repartir de zéro et suivre ton tutoriel et en créer d'autres pour obtenir à  la fin un modèle objet (Managed Object Model) totalement différent et qui ne colle plus du tout avec celui que tu avais au tout début.


    Pour résoudre ça rien de plus simple : tu fais un clean de ton projet (menu Product > Clean, de mémoire) pour qu'au lieu d'essayer de repartir de la dernière compilation et de compiler que ce qui a changé sans écraser ce qui a déjà  été compilé et créé (entre autres le PersistantStore), qu'il efface les résultats des compilations précédentes (y compris le PS) et reparte de zéro avec un binaire et un bundle génère tout propre comme si c'était la premier fois que tu compilais ton projet.


    ça va prendre un poil + de temps qu'une compilation itérative mais au moins la compilation repart d'une feuille blanche et d'un truc clean.
  • berfisberfis Membre
    décembre 2013 modifié #13

    AliGator, ça ne suffira pas. Sous OSX, le fichier créé par une application sans document se trouve dans Bibliothèque:Application Support:com.yourCompany.yourApp. Ecraser le bundle laissera son fichier de données intact. Il faut le bousiller "à  la main".


  • En faites j'ai supprimer le dossier puis j'ai carrément récrée un nouveau projet par contre j'ai mit le même nom ça provient peut-être de la.


     


    Je vais essayer de trouver le fichier car un clean ne change rien


  • J'ai aucun dossier ou fichier du genre yourCompany.yourApp dans Bibliothèque/ApplicationSupport


  • berfisberfis Membre
    décembre 2013 modifié #16

    Regarde ce qu'il y a dans le code fourni par défaut:



    // Returns the directory the application uses to store the Core Data store file. This code uses a directory named "com.idemsoft.TestCoreData" in the user's Application Support directory.
    - (NSURL *)applicationFilesDirectory
    {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *appSupportURL = [[fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
    return [appSupportURL URLByAppendingPathComponent:@com.idemsoft.TestCoreData];
    }


    En clair Bibliothèque : Application Support : com.idemsoft.TestCoreData... dans le cas de mon projet d'exemple. Mais si tu crées ton propre projet, va voir le nom de ta base dans la méthode - (NSURL *)applicationFilesDirectory.


  • Je suis d'accord voici une capture d'écran tu verra j'ai rien


  • Chez moi ça donne ça. Mais attention, si l'application s'est plantée, Core Data ne va pas créer le store...


  • En faites moi je le chercher à  la racine du hdd hors que c'était dans user mais maintenant que j'ai supprimé le fichier storedata mon app se lance plus et j'ai l'erreur suivante dans la console:



    2013-12-28 14:29:17.518 DevisApp[614:303] An uncaught exception was raised
    2013-12-28 14:29:17.519 DevisApp[614:303] Cannot create NSSet from object <NSManagedObjectContext: 0x10014acf0> of class NSManagedObjectContext
    2013-12-28 14:29:17.523 DevisApp[614:303] (
    0 CoreFoundation 0x00007fff8a114b06 __exceptionPreprocess + 198
    1 libobjc.A.dylib 0x00007fff87b7c3f0 objc_exception_throw + 43
    2 CoreFoundation 0x00007fff8a114948 +[NSException raise:format:arguments:] + 104
    3 AppKit 0x00007fff857a815a _NSValueOfClassWithSpecialSpecificErrorMessage + 246
    4 AppKit 0x00007fff857a7bfe -[NSArrayDetailBinder _refreshDetailContentInBackground:] + 1082
    5 AppKit 0x00007fff85796699 -[NSObject(NSKeyValueBindingCreation) bind:toObject:withKeyPath:options:] + 641
    6 AppKit 0x00007fff8561f09a -[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:] + 1012
    7 AppKit 0x00007fff855fe11d loadNib + 317
    8 AppKit 0x00007fff855fd649 +[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:] + 219
    9 AppKit 0x00007fff855fd47e -[NSBundle(NSNibLoading) loadNibNamed:owner:topLevelObjects:] + 200
    10 AppKit 0x00007fff855fd25e +[NSBundle(NSNibLoading) loadNibNamed:owner:] + 360
    11 AppKit 0x00007fff855f99ff NSApplicationMain + 398
    12 DevisApp 0x00000001000029f2 main + 34
    13 libdyld.dylib 0x00007fff880f17e1 start + 0
    14 ??? 0x0000000000000003 0x0 + 3
    )
    2013-12-28 14:29:17.532 DevisApp[614:303] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot create NSSet from object <NSManagedObjectContext: 0x10014acf0> of class NSManagedObjectContext'
    *** First throw call stack:
    (
    0 CoreFoundation 0x00007fff8a114b06 __exceptionPreprocess + 198
    1 libobjc.A.dylib 0x00007fff87b7c3f0 objc_exception_throw + 43
    2 CoreFoundation 0x00007fff8a114948 +[NSException raise:format:arguments:] + 104
    3 AppKit 0x00007fff857a815a _NSValueOfClassWithSpecialSpecificErrorMessage + 246
    4 AppKit 0x00007fff857a7bfe -[NSArrayDetailBinder _refreshDetailContentInBackground:] + 1082
    5 AppKit 0x00007fff85796699 -[NSObject(NSKeyValueBindingCreation) bind:toObject:withKeyPath:options:] + 641
    6 AppKit 0x00007fff8561f09a -[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:] + 1012
    7 AppKit 0x00007fff855fe11d loadNib + 317
    8 AppKit 0x00007fff855fd649 +[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:] + 219
    9 AppKit 0x00007fff855fd47e -[NSBundle(NSNibLoading) loadNibNamed:owner:topLevelObjects:] + 200
    10 AppKit 0x00007fff855fd25e +[NSBundle(NSNibLoading) loadNibNamed:owner:] + 360
    11 AppKit 0x00007fff855f99ff NSApplicationMain + 398
    12 DevisApp 0x00000001000029f2 main + 34
    13 libdyld.dylib 0x00007fff880f17e1 start + 0
    14 ??? 0x0000000000000003 0x0 + 3
    )
    libc++abi.dylib: terminate called throwing an exception
    (lldb)
  • berfisberfis Membre
    décembre 2013 modifié #20

    Elle est là , l'erreur:


    Cannot create NSSet from object <NSManagedObjectContext: 0x10014acf0> of class NSManagedObjectContext


     



    Tes entités Core Data sont des NSManagedObject. Le NSManagedObjectContext, c'est l'environnement abstrait, une sorte d'espace de travail, dans lequel Core Data manipule les objets, les crée, les marque pour la destruction, et finalement les enregistre sous forme de graphe dans un NSPersistantStore géré par le NSPersistantStoreCoordinator.


     


    Tout est expliqué là , RTFM :


    https://developer.apple.com/library/mac/documentation/cocoa/conceptual/coredata/cdProgrammingGuide.html#//apple_ref/doc/uid/TP30001200-SW1


  • Moi et l'anglais ça fait deux donc pas facile la doc  ;)


  • James T. Kirk: Well, I hate to break this to you, but Starfleet operates in space.  :D 


  • J'ai presque réussi à  remplir ma NSTableView via CoreData mais (car il y toujours un mais) j'ai une cellule avec 2 NSTextField mais seul un se remplit celui par défault je n'arrive à  remplir celui que j'ai rajouté.


     


    J'ai essayé en le reliant à  mon AppDelegate.h



    @property (weak) IBOutlet NSTextField *textFieldDateTableViewDevis;

    Puis de le remplir dans la méthode viewForTableColumn



    - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
    {
    NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];

    if(tableView == self.tableViewEntreprise) {
    if ([tableColumn.identifier isEqualToString:@EntrepriseColumn]) {
    Entreprise *ent = [self.entreprise objectAtIndex:row];

    cellView.textField.stringValue = ent.name;
    cellView.backgroundStyle = NSBackgroundStyleLowered;

    return cellView;
    }
    } else if(tableView == self.tableViewDevis) {
    if ([tableColumn.identifier isEqualToString:@numberDevisColumn]) {
    Devis *devis = [self.devis objectAtIndex:row];

    cellView.textField.stringValue = [NSString stringWithFormat:@%@", devis.number];

    return cellView;
    } else if ([tableColumn.identifier isEqualToString:@nameDevisColumn]) {
    Devis *ent = [self.devis objectAtIndex:row];

    cellView.textField.stringValue = ent.name;

    NSDateFormatter *format = [[NSDateFormatter alloc] init];
    [format setDateFormat:@MMM dd, yyyy];

    self.textFieldDateTableViewDevis.stringValue = [format stringFromDate:ent.date];

    return cellView;
    }
    }

    return cellView;
    }

    Je vous met un screen pour vous montrer ma cellule 


  • berfisberfis Membre
    décembre 2013 modifié #24

    Ben, tu ne remplis qu'un champ dans ta méthode, non?


     


    cellView.textField.stringValue = ent.name;  // ou autre valeur


     

    C'est normal que l'autre reste vide.

     

    Avec les bindings, tu passes par objectValue.<propriété de l'objet/attribut de l'entité Core Data>

  • Et sans les bindings y a bien une solution?


  • Bah... celle que tu as utilisée, puisqu'elle remplit l'un des champs! Reste à  trouver le bon Model Key Path pour remplir l'autre.


  • Je ne passe pas par un arraycontroller donc le Model Key Path ne sert pas


  • ça n'a pas forcément à  voir avec un arrayController, cela signifie "le nom (ou "chemin" si tu as affaire à  key.subKey) de la propriété du modèle". Ici, ton modèle c'est une dataSource, mais ça ne change rien...


     


    Ton cellView.textField.stringValue est un Model key path valide. Il te faut trouver celui de ton 2e champ.


  • Et comment je fais pour trouver le bon model key path


  • Mais... c'est toi qui l'as programmé, il doit bien être quelque part dans ton code. Maintenant, moi, les datasource, c'est pas ma tasse de thé. Essaie de faire une recherche dans les subviews de la view qui demande à  s'afficher, quitte à  planter un IBOutlet sur ce deuxième champ et... ah non, pardon, pas de bindings.


     


    Sur ce site, on a plein de gens qui ne jurent que par les datasource, c'est dommage qu'ils ne te renseignent pas, mais il est vrai que cette période de l'année est dévolue aux festivités et non à  la programmation, alors patience... 


  • berfisberfis Membre
    janvier 2014 modifié #31

    Bon, tu as affaire à  une cellView. Elle possède par défaut deux champs:


    - textField (celui que tu utilises)


    - imageView (que tu n'utilises pas)


     


    Mais il y en a un autre: objectValue. C'est l'objet représenté dans ta vue, et donc le chemin vers son contenu. A mon avis (moi j'utilise les bindings, mais ça devrait marcher dans ta dataSource):


     


    cellView.objectValue.premierChamp.stringValue = monPremierNom;



    cellView.objectValue.deuxiemeChamp.stringValue = monDeuxiemeNom;


     

    Il ne reste plus, dans IB, qu'à  établir le binding (eh oui, comment la vue pourrait-elle le savoir autrement?):

    <premier champ> : value = objectValue.premierChamp


    <deuxième champ> : value = objectValue.deuxiemeChamp

     

    Je n'ai pas testé, mais à  mon avis ça devrait marcher.

     


Connectez-vous ou Inscrivez-vous pour répondre.