2009-11-10 10 views
38

He creado una biblioteca estática que hace un uso intensivo de la infraestructura de datos básicos. 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 objetivo de la biblioteca era ocultar los detalles de implementación al máximo posible.datos principales en una biblioteca estática para el iPhone

En un apartado question, me informaron que no puedo agrupar recursos con una biblioteca (lo que ahora tiene mucho sentido para mí).

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

Respuesta

30

También creé mi propia biblioteca estática que utiliza Core Data. Además de la biblioteca estática, tengo otro objetivo 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 compilación Build Sources, donde estoy compilando 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 utilizar los datos básicos con la madre desde el haz tiene que crear un modelo de objeto gestionado fusionado en su código (que podría ser el principal proyecto tiene algún modelo de datos básicos también):

 

- (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; 
} 

 

Por simplemente incluyendo el paquete, no tendrá que dar el modelo xcdata, solo se debe incluir el archivo compilado de la madre.

+0

Sascha - esto funciona bastante bien. El archivo MOM todavía se puede leer en XCode, pero al menos es mejor que mostrar un buen diagrama de modelo de datos. – Vickram

+8

Sascha: Sé que ha pasado un tiempo desde su respuesta aquí, pero me preguntaba si podría detallar cómo configura sus objetivos y fases de compilación para que un proyecto que utiliza una biblioteca estática pueda ver e incluir el archivo compilado de la madre. Actualmente estoy construyendo un marco estático que también usa CoreData, y no pude encontrar la manera de hacerlo. Estoy usando lipo para compilar dos archivos .a separados (versiones de dispositivo y simulador) en un solo paquete de biblioteca estática. –

2

No, la limitación en el uso de marcos no son de Apple en una aplicación para el iPhone realmente cambia el juego de dependencia en relación con OS X. La mayoría iPhone "marcos" (por ejemplo, la caja de herramientas de Google para Mac, Parcela Core, etc.) en realidad recomiendan que incluya 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í.

57

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

  1. Crear un nuevo proyecto XCode biblioteca estática llamados MyStaticLibrary

  2. Crear un archivo llamado .xcdatamodel en MyStaticLibraryMyStaticLibraryModels.xcdatamodel, añadir algunos Entity s, a continuación, generar los encabezados y las implementaciones. Cuando construya el objetivo MyStaticLibrary, generará un archivo binario libMyStaticLibrary.a, pero no incluirá el archivo compilado .mom. Para eso tenemos que crear un paquete.

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

  4. Arrastre MyStaticLibraryModels.xcdatamodel en la fase de construcción Compile Sources del MyStaticLibraryModels Objetivo. Cuando construya el objetivo MyStaticLibraryModels, generará un archivo llamado MyStaticLibraryModels.bundle y contendrá el archivo compilado NSManagedObjectModel, MyStaticLibraryModels.mom.

  5. Después de construir tanto las MyStaticLibrary y MyStaticLibraryModels objetivos, arrastre libMyStaticLibrary.a (junto con los archivos de cabecera Modelo asociados) y MyStaticLibraryModels.bundle en su proyecto de acogida, MyAwesomeApp.

  6. MyAwesomeApp usa CoreData, tiene su propio archivo .xcdatamodel que se compilará en un archivo .mom durante su propio proceso de compilación. Queremos fusionar este archivo .mom con el que importamos en MyStaticLibraryModels.bundle. En algún lugar del proyecto MyAwesomeApp, hay un método que devuelve MyAwesomeApp s NSManagedObjectModel. La plantilla generada Apple por este método es el siguiente:

...

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

Vamos a alterar esta fusionar y devolver ambos de nuestros NSManagedObjectModel s, s MyAwesomApp y MyStaticLibraryModels, como una sola , combinado NSManagedObjectModel 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 la Entity s de MyAwesomeApp y MyStaticLibrary.

+0

Excelente respuesta, gracias. –

+0

Estoy usando Xcode4 y siguiendo los pasos anteriores, logré crear un paquete con una madre, incluido y usado para crear un coordinador y un contexto. Sin embargo, cuando trato de insertar una nueva entidad que estoy seguro que es suficiente, recibí el mensaje de error "no se pudo localizar la entidad llamada ...". Además, si trato de contar todas las entidades modelo, tengo 0. ¿Alguna adivinanza? – Leonardo

+1

Buena solución. La clave que @prairedogg pasa por alto (y me perdí) es que: Xcode creará una fase COPY RESOURCES, pero Xcode está codificado para IGNORAR COPY RESOURCES PHASES EN UN OBJETIVO DE BIBLIOTECA ESTÁTICA. Si incluye su paquete en su biblioteca, nada sucederá. Tienes que incluir tu paquete en tu aplicación final por separado (obvio cuando lo piensas; estamos trabajando en el error de que Xcode no copia las cosas que supuestamente debe copiar;)). – Adam

2

tengo un poco de biblioteca con coredata también. he encontrado esta plantilla para gestionar un marco con Recursos incrustar

Es muy simple de usar en un nuevo proyecto (más difícil de aplicar en la existente) pero para framewoks construir, es realmente :-) fresco

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

2

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 ha accedido a los recursos del paquete, por lo que el paquete ya estaba cargado antes de que se ejecutara este código.

0

Swift 2 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! 
}() 
0

Tenga en cuenta que en lugar de utilizar xcdatamodel/madre que presentar 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í está un ejemplo sencillo 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 la creación de modelo de código: https://www.cocoanetics.com/2012/04/creating-a-coredata-model-in-code/

También basado en este enfoque que he creado un pequeño y fácil de usar biblioteca que puede ajustarse a sus necesidades llamadas LSMiniDB para que pueda verificarlo también.

Cuestiones relacionadas