Pregunta

He creado una biblioteca estática que hace un uso intensivo del marco de datos principal. Puedo usar con éxito la biblioteca en mi proyecto externo, pero solo si incluyo el archivo .xcdatamodel en el proyecto principal. Eso es menos que ideal, ya que el punto de la biblioteca era ocultar los detalles de implementación al máximo posible.

En un pregunta, Me informaron que no puedo agrupar recursos con una biblioteca (que ahora tiene mucho sentido para mí).

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

¿Fue útil?

Solución

También creé mi propia biblioteca estática que usa datos principales. Además de la biblioteca estática, tengo otro objetivo de paquete en el proyecto donde tengo un elemento de recursos de paquete de copias, que copia algunas imágenes y cosas así en el paquete y una fase de construcción de fuentes de compilación, donde estoy compilando el XCDATAmodel.

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

Para usar datos principales con la MOM desde el paquete, debe crear un modelo de objeto administrado fusionado en su código (podría ser el proyecto principal también tiene algún modelo de datos básicos):


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


Al incluir el paquete que no tendrá que dar el XCDATAmodel, solo se debe incluir el archivo de MOM compilado.

Otros consejos

La respuesta de Sascha me puso en el camino correcto. Fusionando un compilado .mom archivo de una biblioteca estática al .mom El archivo de un proyecto de host era relativamente simple. Aquí hay un ejemplo trivial:

  1. Cree un nuevo proyecto de biblioteca de Xcode Static llamado MyStaticLibrary

  2. Crear un archivo .xcdatamodel en MyStaticLibrary llamó MyStaticLibraryModels.xcdatamodel, agrega algo EntityS, luego genere los encabezados e implementaciones. Cuando construyes el MyStaticLibrary objetivo, generará un libMyStaticLibrary.a archivo binario, pero no incluirá el compilado .mom expediente. Para eso tenemos que crear un paquete.

  3. Crear un nuevo objetivo de compilación de tipo Loadable Bundle, encontrado debajo MacOS X > Cocoa, llamemos al nuevo objetivo MyStaticLibraryModels.

  4. Arrastrar MyStaticLibraryModels.xcdatamodel en el Compile Sources Fase de construcción del MyStaticLibraryModels Objetivo. Cuando construyes el MyStaticLibraryModels Objetivo, generará un archivo llamado MyStaticLibraryModels.bundle y contendrá el compilado NSManagedObjectModel expediente, MyStaticLibraryModels.mom.

  5. Después de construir ambos MyStaticLibrary y MyStaticLibraryModels Objetivos, arrastre libMyStaticLibrary.a (junto con cualquier archivo de encabezado de modelo asociado) y MyStaticLibraryModels.bundle en su proyecto de anfitrión, MyAwesomeApp.

  6. MyAwesomeApp usos CoreData, tiene su propio .xcdatamodel Archivo que se compilará en un archivo .mom durante su propio proceso de compilación. Queremos fusionar esto .mom Archivo con el que importamos MyStaticLibraryModels.bundle. En algún lugar del MyAwesomeApp Proyecto, hay un método que devuelve MyAwesomeApps 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_;
}

Alteraremos esto para fusionar y devolverse ambos NSManagedObjectModels, MyAwesomApparena MyStaticLibraryModels, como una sola, combinada NSManagedObjectModel al igual que:

- (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 fusionado NSManagedObjectModel con el Entitys de ambos MyAwesomeApp y MyStaticLibrary.

No, la limitación del uso de marcos sin applejo en una aplicación para iPhone realmente cambia el juego de dependencia en relación con OS X. La mayoría de los "marcos" de iPhone (por ejemplo, la caja de herramientas de Google para Mac, la trama central, etc.) en realidad recomendar que incluye 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 marco 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ígale a sus usuarios que no utilicen los detalles de implementación y lo deje así.

También tengo una biblioteca con Coredata. He encontrado esta plantilla para administrar un marco con resonaciones de incrustación

Es realmente simple de usar en un nuevo proyecto (más difícil de aplicar en existente), pero para la construcción de FrameWoks, es realmente genial :-)

https://github.com/kstenerud/ios-universalframework

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 madre.

En su caso, probablemente ya haya accedido a los recursos desde el 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 hacer esto en Xcode 5: http://bharathnagararajrao.wordpress.com/2014/02/14/working-with-core-data-in-a-static-library/

Tenga en cuenta que en lugar de usar 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 la creación del modelo de código: https://www.cocoanetics.com/2012/04/creating-a-coredata-model-in-code/

También en base a este enfoque, creé una biblioteca pequeña y fácil de usar que podría satisfacer sus necesidades llamadas LSMinidB Entonces también puedes comprobarlo.

Versión 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!
}()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top