Rajouter un modèle Core Data après coup

berfisberfis Membre
mai 2013 modifié dans API AppKit #1

Bonjour,


 


Je travaille sur une application sans document. Je sais que Core Data est un modèle avec persistance, mais en fait je compte uniquement me servir du modèle pour générer des objets dont la durée de vie sera celle de la session.


 


Je considère en effet qu'un modèle CD est agréable à  utiliser, et regroupe clairement la partie modèle. Actuellement je travaille avec un fichier plist, c'est assez fastidieux, surtout que j'aimerais bien essayer de dériver des objets qui diffèrent peu les uns des autres (ce qui est impossible à  faire avec une plist!)


 


Y a-t-il donc moyen, après que le projet a été créé sans Core Data, de l'ajouter et de s'en servir? et si oui comment? Je n'ai pas besoin de tout le code par défaut que Xcode ajoute dans un projet CD...


 


Est-ce déjà  arrivé à  l'un d'entre vous?


Réponses

  • skimpyskimpy Membre

    Bonjour berfis,


     


    Oui, tu peux ajouter Core Data par la suite sans avoir besoin d'utiliser le template généré par Xcode. Voici un exemple (d'une méthode que j'appelle dans applicationDidFinishLaunching:, c'est un extrait du livre de Marcus Zarra) :



    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@MyModel
    withExtension:@momd];

    ZAssert(modelURL, @Failed to load model URL);

    NSManagedObjectModel *mom = nil;
    mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    ZAssert(mom, @Failed to initialize model);

    NSPersistentStoreCoordinator *psc = nil;
    psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
    ZAssert(self.psc, @Failed to initialize persistent store coordinator);

    NSManagedObjectContext *moc = nil;
    NSManagedObjectContextConcurrencyType ccType = NSMainQueueConcurrencyType;
    moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:ccType];
    [moc setPersistentStoreCoordinator:self.psc];
    [self setManagedObjectContext:moc];

    dispatch_queue_t queue = NULL;
    queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *directoryArray = [fileManager URLsForDirectory:NSApplicationSupportDirectory
    inDomains:NSUserDomainMask];

    NSURL *storeURL = nil;
    storeURL = [directoryArray lastObject];
    storeURL = [storeURL URLByAppendingPathComponent:@MyCD.sqlite];

    NSError *error = nil;
    NSPersistentStore *store =nil;

    store = [self.psc addPersistentStoreWithType:NSSQLiteStoreType
    configuration:nil
    URL:storeURL
    options:options
    error:&error];

    if (!store) {
    ALog(@Error adding persistent store to coordinator %@\n%@", [error localizedDescription], [error userInfo]);
    }
    DLog(@Core Data initialized ...);
    });


    Par contre intégrer Core Data tout à  la fin de ton projet, je ne sais pas si c'est une super idée car il va y avoir pas mal de transformation dans ton code.

  • AliGatorAliGator Membre, Modérateur

    Je te conseille (comme je conseille à  tout le monde) d'utiliser le framework MagicalRecord, qui facilite l'utilisation de CoreData de façon assez conséquente, en te fournissant des méthodes plus simples à  comprendre et à  manipuler.


     


    Par exemple, quand tu fais un nouveau projet Xcode avec le template CoreData (ou quand tu regardes le code que t'a filé skimpy qui est un peu dans le même genre), ça peut faire peur de voir le nombre de lignes de code qu'il y a à  rajouter pour initialiser le contexte CoreData et trainer des contextes partout et tout.


     


    Avec MagicalRecord, tu as des méthodes toutes faites qui te font ça toutes seules, ce qui fait que tu as juste à  appeler la méthode

    [MagicalRecord setupCoreDataStack];
    et il fait tout ce qu'il faut pour toi. En pratique ça revient à  la même chose que d'écrire toutes les lignes du template Apple ou de skimpy toi-même grosso-modo, mais c'est quand même plus rapide à  prendre en main, et à  rajouter à  ton projet existant qui est pour l'instant sans CoreData !

     


    Plus fort encore, tu dis ne pas avoir besoin de persistance fichier, et donc que tout ton modèle peut tout à  fait être uniquement en mémoire, sans avoir besoin d'écrire les données sur disque pour les retrouver au prochain lancement. Là  encore, pas de problème, avec MagicalRecord tu as une méthode

    [MagicalRecord setupCoreDataStackInMemory];
    qui te configure tout ton contexte CoreData... mais sans Persistent Store fichier. Tout est gardé en mémoire et oublié dès que tu quittes l'appli. Donc si tu n'as pas besoin de persistance, c'est tout à  fait ce qu'il te faut, puisqu'en plus d'éviter de sauvegarder ton modèle alors que tu ne veux pas / n'en a pas besoin, ça t'évite de forcer à  tout remettre à  zéro à  chaque lancement.
  • berfisberfis Membre

    Merci pour vos réponses!


     


    @skimpy : dans les lignes que tu m'as suggérées, on voit clairement que le code crée un PersistentStoreCoordinator, je me demandais si c'était un incontournable de Core Data, genre: je-ne-t'initialise-pas-ton-modèle-si-tu-ne-me-laisse-pas-ajouter-mon-storeCoordinator-qui-gère-ton-sqlite-comme-par-magie...


     


    Mon idée c'est juste pourvoir instancier des objets depuis un modèle (tu me diras, dans ce cas pourquoi de pas créer de simples classes dérivées du Framework, et tu auras raison). C'est juste que c'est plus clair de la façon dont c'est présenté, graphiquement, dans l'éditeur de modèle. ça m'aide à  y voir plus clair que dans une douzaine de fichiers .h...


     


    @AliGator : j'ai jeté un coup d'oeil à  MR -- sans réussir à  le faire tourner, j'ai sans doute manqué une marche dans l'installation. Mais je me demande que est le prix à  payer (en taille) pour employer cette surcouche de Core Data. Je ne compte pas utiliser de contrôleurs, ni de fetchs, ni de bindings, juste me servir du modèle pour instancier des objets. Mais je me rends compte qu'on instancie des objets que dans un contexte, lequel gère le undo... et la persistance. Visiblement, pas moyen de fractionner Core Data pour n'en utiliser qu'une partie... ou si?


  • AliGatorAliGator Membre, Modérateur
    mai 2013 modifié #5

    En effet dans CoreData tu définis des entités (un peu comme des tables d'une BDD) avec l'outil graphique et a partir de là  tu lui demandes de générer des classes modèle. Mais ces classes modèle sont des sous-classes de NSManagedObject et doivent être crées dans un NSManagedObjectContext et tout tourne autour de ça, entre autres pour gérer les undo mais aussi les relationShips & co entre les entités.


     


    ---


     


    Si tu veux quand même utiliser ça, l'avantage d'utiliser MagicalRecord (tu as suivi le README et les explications sur le site ? C'est pourtant pas sorcier à  installer, ça s'intègre comme n'importe quelle librairie tierce, soit en copiant les sources (beurk, je déconseille), soit via un Workspace (comme j'ai expliqué lors de ma présentation CocoaHeads Rennes #12 que tu peux retrouver en vidéo), soit en utilisant CocoaPods...) c'est qu'ensuite tu fais :


     - [MagicalRecord setupCoreDataStackInMemory] au démarrage de ton appli, et tu as tout de configuré en une seule ligne pour une utilisation de CoreData uniquement en mémoire (sans sauvegarde en base SQLite derrière ou quoi)


     - et ensuite tu fais [MaClasseModele createEntity] pour créer une instance de MaClasseModèle (comme tu ferais [MaClasseModele new] ou [[MaClasseModele alloc] init] pour un objet standard), createEntity étant une méthode rajoutée par MagicalRecord pour créer une entité sans avoir à  t'embêter à  préciser le ManagedObjectContext à  utiliser (en vérité MR garde un MOC de côté, qu'il appelle le defaultManagedObjectContext, et quand tu appelles createEntity c'est ce MOC qu'il utilise pour instancier l'entité)


     


    Donc au final, c'est possible de l'utiliser comme tu veux, avec ou sans MagicalRecord mais bien sûr c'est 100x plus simple avec MR qui va te masquer tous les détails des lignes pour configurer ta stack CoreData et tous les détails de gestion de MOC sous le capot.


     


    ---


     


    Après, en pratique, je te conseille quand même plutôt de créer toi-même ton modèle objet avec des classes de Foundation, genre des sous-classes custom de NSObject, car certes tu n'auras pas l'outil que tu as avec CoreData pour générer ton ManagedObjectModel (MOM), mais ça restera moins lourd au niveau exécution à  gérer en général, et plus adapté pour ton besoin (où tout ce qu'apporte CoreData comme avantages tu ne t'en servirais pas, donc c'est un peu bête de sortir ce fmk pour pas l'utiliser)


  • skimpyskimpy Membre
    mai 2013 modifié #6
    Pour moi t'es obligé d'avoir un PersistentStore (tu peux remplacer le SQLIStore par un NSInMemoryStore si tu veux seulement stocker en mémoire).

    Pour le Undo tu n'es pas obligé de l'utiliser, un setUndoManager:nil sur ton MOC permet de le désactiver (c'est ce que la doc d'Apple recommande de faire lorsque tu fais des imports en masse).
  • berfisberfis Membre
    mai 2013 modifié #7

    Bon... merci pour les conseils, je me doutais un peu de la réponse mais... ce n'était qu'un doute. Le voici levé.


     


    Je vais donc continuer à  faire comme jusqu'à  présent: je crée mes modèles... dans des tableaux Numbers, je rajoute plein de couleurs, et quand je vois qui dérive de qui, qui est une classe abstraite, et qui a une propriété qui pointe sur qui... je lance Xcode et je commence à  coder.


     


    Vous, je ne sais pas, mais ce que j'aime avec Core Data, c'est sa façon de placer le modèle au centre (puisqu'elle abstrait le reste). J'ai vu au dernier cours iOS (donc peu profitable pour moi...) des collègues "ch... du code"et multiplier les contrôleurs-de-contrôleurs-de-contrôleurs pour ficeler de petits amours d'applications à  8Mo dont on a un peu de peine à  savoir ce qu'elles faisaient... et surtout comment.


     


    A mon avis, si l'intelligence d'une application est dans la partie Contrôleurs et sa beauté dans la partie Vue, son analyse est dans la partie Modèle. Mais ce n'est qu'un avis.


  • AliGatorAliGator Membre, Modérateur
    Oui on est d'accord, un bon MDD est le coe“ur d'une bonne application et bien penser son MDD au démarrage est important.


    Perso je fais mes diagrammes de MDD avec l'excellent OmniGraffle. Il est bon de savoir que si à  ma connaissance on ne peut pas générer les classes Objective-C à  partir d'un diagramme de MDD qu'on a fait avec OmniGraffle, par contre il sait faire l'inverse : on peut ouvrir un fichier .xcodeproj avec OmniGraffle et il nous génère le diagramme de classes !
  • berfisberfis Membre

    Merci AliGator pour le lien d'Omnigraffle. J'ai téléchargé la version d'essai, c'est clair, propre et ça a l'air très complet! Je pense que durant les 14 jours d'essai j'aurai le temps de me faire la main... Et c'est clair que générer un diagramme de classe (sans les propriétés) à  partir d'Xcode c'est un sacré temps de gagné!  Ca doit leur avoir fait chaud au coeur de générer le diagramme d'Omnigraffle... avec Omnigraffle ! :)


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