datos básicos en una biblioteca estática para el iPhone

Creé una biblioteca estática que hace un uso intensivo de la infraestructura Core Data. Puedo utilizar con éxito la biblioteca en mi proyecto externo, pero SOLAMENTE si incluyo el archivo .xcdatamodel en el proyecto principal. Eso es menos que ideal, ya que el objective de la biblioteca era ocultar los detalles de implementación al máximo posible.

En otra pregunta , me informaron que no puedo agrupar recursos con una biblioteca (lo cual tiene mucho sentido para mí ahora).

Entonces, ¿hay alguna manera de permitir programáticamente que el modelo sea “descubierto” sin tener que incluir el modelo en el proyecto principal?

También creé mi propia biblioteca estática que utiliza Core Data. Además de la biblioteca estática, tengo otro objective de paquete en el proyecto donde tengo un elemento de Copy Bundle Resources, que copia algunas imágenes y cosas así en el paquete y una fase de comstackción Build Sources, donde estoy comstackndo el modelo xcdata.

El paquete final contendrá todos los archivos necesarios. En su proyecto principal que depende de la biblioteca estática, debe incluir ese paquete también. Su proyecto principal ahora tendrá acceso al archivo madre que se necesita para usar los datos centrales.

Para usar datos básicos con la madre del paquete, debe crear un modelo de objeto gestionado fusionado en su código (puede ser que el proyecto principal también tenga algún modelo de datos principal):

- (NSManagedObjectModel *) mergedManagedObjectModel { if (!mergedManagedObjectModel) { NSMutableSet *allBundles = [[[NSMutableSet alloc] init] autorelease]; [allBundles addObjectsFromArray: [NSBundle allBundles]]; [allBundles addObjectsFromArray: [NSBundle allFrameworks]]; mergedManagedObjectModel = [[NSManagedObjectModel mergedModelFromBundles: [allBundles allObjects]] retain]; } return mergedManagedObjectModel; } 

Con solo incluir el paquete, no tendrá que dar el modelo xcdata, solo se debe incluir el archivo comstackdo de la madre.

La respuesta de Sascha me puso en el camino correcto. La fusión de un archivo .mom comstackdo de una biblioteca estática en el archivo .mom de un proyecto de host fue relativamente simple. Aquí hay un ejemplo trivial:

  1. Cree un nuevo proyecto de XCode Static Library llamado MyStaticLibrary

  2. Cree un archivo .xcdatamodel en MyStaticLibrary llamado MyStaticLibraryModels.xcdatamodel , agregue algunas Entity , luego genere los encabezados y las implementaciones. Cuando crea el destino MyStaticLibrary , generará un archivo binario libMyStaticLibrary.a , pero no incluirá el archivo .mom comstackdo. Para eso tenemos que crear un paquete.

  3. Cree un nuevo objective de comstackción del tipo Loadable Bundle , que se encuentra en MacOS X > Cocoa , llamemos al nuevo Target MyStaticLibraryModels .

  4. Arrastre MyStaticLibraryModels.xcdatamodel en la fase de Compile Sources MyStaticLibraryModels.xcdatamodel Compile Sources del MyStaticLibraryModels Target. Cuando construya el Target MyStaticLibraryModels , generará un archivo llamado MyStaticLibraryModels.bundle y contendrá el archivo comstackdo NSManagedObjectModel , MyStaticLibraryModels.mom .

  5. Después de MyStaticLibrary tanto MyStaticLibrary como MyStaticLibraryModels Targets, arrastre libMyStaticLibrary.a (junto con los archivos de encabezado de modelo asociados) y MyStaticLibraryModels.bundle en su proyecto de host, MyAwesomeApp .

  6. MyAwesomeApp usa CoreData , tiene su propio archivo .xcdatamodel que se comstackrá en un archivo .mom durante su propio proceso de comstackción. Queremos fusionar este archivo .mom con el que MyStaticLibraryModels.bundle en MyStaticLibraryModels.bundle . En algún lugar del proyecto MyAwesomeApp , hay un método que devuelve el objeto MyAwesomeApp NSManagedObjectModel . La plantilla generada por Apple para este método se ve así:

 - (NSManagedObjectModel *)managedObjectModel { if (managedObjectModel_ != nil) { return managedObjectModel_; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"]; managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return managedObjectModel_; } 

NSManagedObjectModel esto para fusionar y devolver AMBOS de nuestros NSManagedObjectModel , MyAwesomApp y MyStaticLibraryModels , como un único NSManagedObjectModel combinado así:

 - (NSManagedObjectModel *)managedObjectModel { if (managedObjectModel_ != nil) { return managedObjectModel_; } NSMutableArray *allManagedObjectModels = [[NSMutableArray alloc] init]; NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyAwesomeApp" withExtension:@"momd"]; NSManagedObjectModel *projectManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; [allManagedObjectModels addObject:projectManagedObjectModel]; [projectManagedObjectModel release]; NSString *staticLibraryBundlePath = [[NSBundle mainBundle] pathForResource:@"MyStaticLibraryModels" ofType:@"bundle"]; NSURL *staticLibraryMOMURL = [[NSBundle bundleWithPath:staticLibraryBundlePath] URLForResource:@"MyStaticLibraryModels" withExtension:@"mom"]; NSManagedObjectModel *staticLibraryMOM = [[NSManagedObjectModel alloc] initWithContentsOfURL:staticLibraryMOMURL]; [allManagedObjectModels addObject:staticLibraryMOM]; [staticLibraryMOM release]; managedObjectModel_ = [NSManagedObjectModel modelByMergingModels:allManagedObjectModels]; [allManagedObjectModels release]; return managedObjectModel_; } 

Esto devolverá el NSManagedObjectModel fusionado con Entity s de MyAwesomeApp y MyStaticLibrary .

No, la limitación de usar frameworks que no son de Apple en una aplicación de iPhone realmente cambia el juego de dependencia en relación con OS X. La mayoría de los “frameworks” de iPhone (por ejemplo, la caja de herramientas de Google para Mac, Core Plot, etc.) realmente recomiendan incluir la fuente en su proyecto de aplicación principal en lugar de vincular un producto (es decir, una biblioteca estática). Creo que el consenso de la comunidad es que, en iPhone, está bien esperar que los consumidores de su infraestructura tengan que hacer un pequeño trabajo “manual” para usar su biblioteca. En su caso, esto incluye el archivo xcdatamodel en el proyecto principal. Al igual que con la mayoría de Objective-C, dígales a sus usuarios que no hagan uso de los detalles de implementación y déjenlo así.

También tengo una biblioteca con coredata. He encontrado esta plantilla para administrar un marco con recursos de inserción

es muy fácil de usar en un nuevo proyecto (más difícil de aplicar en el existente) pero para builds de framewoks, es realmente genial 🙂

https://github.com/kstenerud/iOS-Universal-Framework

La solución de Sascha Konietzke funciona bien, pero hay una advertencia importante que debe proporcionarse para que funcione. El paquete que contiene el modelo debe cargarse primero; de lo contrario, no se incluirá en la matriz y se fusionará en la MOM.

En este caso, probablemente ya haya accedido a los recursos del paquete, por lo tanto, el paquete ya estaba cargado antes de que se ejecutara este código.

La respuesta de Prairiedogg está un poco desactualizada, aquí hay un tutorial sobre cómo hacer esto en Xcode 5: http://bharathnagarajrao.wordpress.com/2014/02/14/working-with-core-data-in-a-static-library/

Tenga en cuenta que, en lugar de utilizar el archivo xcdatamodel / mom, también puede crear su modelo en código (especialmente si tiene un modelo simple) y de esta manera no necesitará crear un paquete adicional para los recursos. Aquí hay un ejemplo simple con una tabla que contiene dos atributos:

 - (NSManagedObjectModel *)coreDataModel { NSManagedObjectModel *model = [NSManagedObjectModel new]; NSEntityDescription *eventEntity = [NSEntityDescription new]; eventEntity.name = @"EventEntity"; eventEntity.managedObjectClassName = @"EventEntity"; NSAttributeDescription *dateAttribute = [NSAttributeDescription new]; dateAttribute.name = @"date"; dateAttribute.attributeType = NSDateAttributeType; dateAttribute.optional = NO; NSAttributeDescription *typeAttribute = [NSAttributeDescription new]; typeAttribute.name = @"type"; typeAttribute.attributeType = NSStringAttributeType; typeAttribute.optional = NO; eventEntity.properties = @[dateAttribute, typeAttribute]; model.entities = @[eventEntity]; return model; } 

Aquí hay un tutorial sobre cómo crear un modelo a partir del código: https://www.cocoanetics.com/2012/04/creating-a-coredata-model-in-code/

También basado en este enfoque, creé una biblioteca pequeña y fácil de usar que podría adaptarse a sus necesidades llamada LSMiniDB para que pueda verificarla también.

Swift 2 versión para la respuesta de Sascha:

 lazy var managedObjectModel: NSManagedObjectModel = { // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model. var allBundles = NSMutableSet() allBundles.addObjectsFromArray(NSBundle.allBundles()) allBundles.addObjectsFromArray(NSBundle.allFrameworks()) let model = NSManagedObjectModel.mergedModelFromBundles(allBundles.allObjects as? [NSBundle]) return model! }()