web-dev-qa-db-fra.com

Comment utiliser ManagedObjectModel de Core Data dans un framework?

J'essaie de migrer une partie spécifique de l'une de mes applications vers un framework afin de pouvoir l'utiliser dans mon application elle-même et dans l'un de ces nouveaux widgets iOS 8 sophistiqués. Cette partie est celle qui gère toutes mes données dans Core Data. C'est assez simple de tout déplacer et d'y accéder. J'ai simplement du mal à accéder à mon fichier momd.

Lors de la création de la NSManagedObjectModel, j'essaie toujours de charger la momd comme illustré dans les modèles de code d'Apple:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

Malheureusement, modelURL reste nil et donc MyApp se bloque lors de l'accès à la pile de données de base avec cette erreur:

2014-08-01 22:39:56.885 MyApp[81375:7417914] Cannot create an NSPersistentStoreCoordinator with a nil model
2014-08-01 22:39:56.903 MyApp[81375:7417914] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Cannot create an NSPersistentStoreCoordinator with a nil model'

Alors, quelle est la bonne façon de faire cela lorsque vous travaillez dans un cadre avec Core Data?

26
flohei

Je suis un peu en retard pour le problème de flohei, mais j'espère que cela aidera tous ceux qui errent. Il est possible que cela fonctionne sans avoir à exécuter script-fu pour copier des ressources!

Par défaut, le modèle Core Data d’Apple vous donne quelque chose comme:

lazy var managedObjectModel: NSManagedObjectModel = {
  let modelURL = NSBundle.mainBundle().URLForResource("MyCuteCoreDataModel", withExtension: "momd")!
  return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

Cela chargerait vos ressources Core Data du bundle principal. L'essentiel ici est le suivant: si le modèle Core Data est chargé dans un framework, le fichier .momd se trouve dans le bundle de ce framework. Au lieu de cela, nous faisons juste ceci:

lazy var managedObjectModel: NSManagedObjectModel = {
    let sexyFrameworkBundleIdentifier = "com.heybaby.xxx"
    let customKitBundle = NSBundle(identifier: sexyFrameworkBundleIdentifier)!
    let modelURL = customKitBundle.URLForResource("MyCuteCoreDataModel", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

Cela devrait vous rendre opérationnel.

Crédit: https://www.andrewcbancroft.com/2015/08/25/sharing-a-core-data-model-with-a-Swift-framework/

18
Jonathan Zhan

Vous devez faire glisser le fichier xcdatamodeld et le déposer dans les phases de construction | Compilez les sources pour les cibles qui utilisent le framework. Ensuite, lorsque la cible s'exécutera, son [NSBundle mainBundle] contiendra le modèle (fichier momd).

13
user3771857

@Ric Santos était presque là. Je pense que vous avez juste besoin d'en faire une extension "maman" plutôt que "momd", alors elle fonctionnera 

lazy var managedObjectModel: NSManagedObjectModel = {
    let modelURL = NSBundle(forClass: self.dynamicType.self).URLForResource(self.dataModelName, withExtension: "mom")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
6
Faqinghere

J'ai peut-être un peu de retard avec cette réponse, mais voici ce qui a résolu mon problème:

Avec mon framework, je fournis également un ensemble de ressources telles que des images et autres éléments. Mettre le fichier xcdatamodeld à cet endroit n'a rien donné car ce fichier est créé avec le projet et vous obtenez un dossier momd dans votre bundle d'applications (qui manque en fait dans notre cas) .. J'ai créé une autre cible, pas un framework, mais une application, je l'ai construite et copiée le momd de son bundle d'applications dans mon bundle séparé du projet (celui qui est fourni avec le framework) . changez l'URL de votre ressource du paquet principal au nouveau:

// ...
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"separate_bundle" ofType:@"bundle"];
NSURL *modelURL = [[NSBundle bundleWithPath:bundlePath] URLForResource:@"your_model" withExtension:@"momd"];
// ...

A bien fonctionné pour moi. La seule chose que je sache, c'est l'App Store Review que je n'ai pas encore compris… donc si vous avez trouvé une meilleure solution, partagez-la.

MODIFIER

J'ai trouvé une meilleure solution. Vous pouvez construire le modèle vous-même. De Guide de programmation de base de données :

Un modèle de données est une ressource de déploiement. En plus des détails de la entités et propriétés dans le modèle, un modèle que vous créez dans Xcode contient des informations sur le diagramme - sa disposition, les couleurs des éléments, etc. Cette dernière information n'est pas nécessaire au moment de l'exécution. Le modèle Le fichier est compilé à l'aide du compilateur de modèle, momc, pour supprimer le fichier informations superflues et rendre le chargement de la ressource au moment de l’exécution en efficace que possible. Un répertoire «source» xcdatamodeld est compilé dans un répertoire de déploiement momd, et un fichier «source» xcdatamodel est compilé dans un fichier de déploiement de maman.

momc se trouve dans/Developer/usr/bin /. Si vous voulez l'utiliser dans votre propres scripts de construction, son utilisation est momc source destination, où source est le chemin du modèle Core Data à compiler et la destination est le chemin de la sortie.

Par "/ Developer/usr/bin /", ils signifient "/ Applications/Xcode.app/Developer/usr/bin/".

Vous pouvez ajouter un script dans votre schéma cible et le compiler automatiquement avant chaque construction (ou après, ne pensez pas que cela compte). Ceci est le cas si vous modifiez le modèle au cours du développement.

Quelque chose comme ça:

mkdir -p "${BUILT_PRODUCTS_DIR}/your_model_name.momd"
momc "${SRCROOT}/your_model_path/your_model_name.xcdatamodeld" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/your_bundle_name.bundle/your_model_name.momd"
4
jackal

La ressource de modèle n'est plus accessible via la mainBundle, vous devez utiliser bundleForClass: comme suit: 

NSURL *modelURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"MyApp" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
2
Ric Santos

Si vous essayez d’avoir des données de base dans votre infrastructure, procédez comme suit.

dans YourFramework - ajouter un nouveau fichier/données de base/modèle de données ... - créer tous les objets ....

Lorsque vous créez un nouveau projet qui utilisera YourFramework, assurez-vous que les données de base sont sur  Use Core Data : On

Cela créera toutes les plaques de chaudière dans AppDelegate.

dans le projet test - ajouter un cadre - ajouter un cadre en tant que cadre intégré - SUPPRIMER le fichier .xcdatamodeld - dans AppDelegate:

changer la méthode - (NSManagedObjectModel *)managedObjectModel en: 

NSBundle * testBundle = [NSBundle bundleWithIdentifier:@"YourFramework bundle id "];

NSURL *modelURL = [testBundle URLForResource:@"Model" withExtension:@"momd"];

YourFramework bundle id est l'identifiant d'ensemble de YourFramework (en général/identifiant d'ensemble)

et Model est le nom de votre fichier .xcdatamodeld dans YourFramework

Cela marche.

J'espère que ça aide.

0
Marko Zadravec

Je suppose que vous n’avez besoin que du modèle de données.

Si tel est le cas, la méthode suivante est systématiquement la méthode la plus efficace pour copier d’un fichier de modèle de données d’un projet à un autre ...

  1. Supprimez toutes les copies actuelles du fichier .xcdatamodeld résidant dans le projet cible.
  2. Fermez Xcode.

    Utiliser le Finder (ou la ligne de commande); 

  3. Sélectionnez votre dossier de projet Xcode contenant le fichier .xcdatamodeld d'origine.
  4. Faites une copie du fichier .xcdatamodeld original.
  5. Déplacez la copie du fichier .xcdatamodeld d'origine vers votre projet cible.

    Ensuite...

  6. Ouvrez Xcode.
  7. A l'aide de la commande de menu "Ajouter des fichiers à> votre projet <", recherchez et ajoutez la copie du fichier .xcdatamodeld d'origine à votre projet.
  8. Renommez le fichier .xcdatamodeld d'origine (si nécessaire) à l'aide de Project Navigator.
  9. "Build & Run" votre projet cible. 

Est-ce que cela aide?

0
andrewbuilder