Основные данные в статической библиотеке для iPhone - PullRequest
39 голосов
/ 11 ноября 2009

Я создал статическую библиотеку, которая интенсивно использует платформу Core Data. Я могу успешно использовать библиотеку во внешнем проекте, но ТОЛЬКО если я включу файл .xcdatamodel в основной проект. Это не идеально, так как целью библиотеки было скрыть детали реализации в максимально возможной степени.

В отдельном вопросе мне сообщили, что я не могу связать ресурсы с библиотекой (что сейчас для меня вполне логично).

Так есть ли способ программно разрешить "обнаружение" модели без включения модели в основной проект?

Ответы [ 8 ]

58 голосов
/ 06 января 2011

Ответ Саши направил меня на правильный путь. Объединить скомпилированный файл .mom из статической библиотеки в файл .mom из основного проекта было относительно просто. Вот тривиальный пример:

  1. Создание новой статической библиотеки XCode проект под названием MyStaticLibrary

  2. Создайте файл .xcdatamodel в MyStaticLibrary с именем MyStaticLibraryModels.xcdatamodel, добавьте несколько Entity s, затем сгенерируйте заголовки и реализации. Когда вы создаете цель MyStaticLibrary, вы создаете двоичный файл libMyStaticLibrary.a, но он не будет включать скомпилированный файл .mom. Для этого мы должны создать пакет.

  3. Создайте новую цель сборки типа Loadable Bundle, найденную в MacOS X > Cocoa, давайте назовем новую цель MyStaticLibraryModels.

  4. Перетащите MyStaticLibraryModels.xcdatamodel в фазу построения Compile Sources цели MyStaticLibraryModels. При создании цели MyStaticLibraryModels вы создадите файл с именем MyStaticLibraryModels.bundle, который будет содержать скомпилированный файл NSManagedObjectModel, MyStaticLibraryModels.mom.

  5. После создания целей MyStaticLibrary и MyStaticLibraryModels перетащите libMyStaticLibrary.a (вместе со всеми связанными файлами заголовков модели) и MyStaticLibraryModels.bundle в ваш хост-проект, MyAwesomeApp.

  6. MyAwesomeApp использует CoreData, имеет собственный .xcdatamodel файл, который будет скомпилирован в файл .mom во время его собственного процесса сборки. Мы хотим объединить этот .mom файл с тем, который мы импортировали в MyStaticLibraryModels.bundle. Где-то в проекте MyAwesomeApp есть метод, который возвращает MyAwesomeApp s NSManagedObjectModel. Шаблон, сгенерированный Apple для этого метода, выглядит следующим образом:

...

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

Мы изменим это, чтобы объединить и вернуть ОБА наших NSManagedObjectModel s, MyAwesomApp s и MyStaticLibraryModels, как одно объединенное NSManagedObjectModel, вот так:

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

Это вернет объединенное NSManagedObjectModel с Entity s от MyAwesomeApp и MyStaticLibrary.

30 голосов
/ 14 ноября 2009

Я также создал свою собственную статическую библиотеку, которая использует Core Data. Помимо статической библиотеки у меня есть еще одна цель комплекта в проекте, где у меня есть элемент «Копировать комплекты ресурсов», который копирует некоторые изображения и тому подобное в комплект и на фазе сборки источников компиляции, где я собираю xcdatamodel.

Финальный комплект будет содержать все необходимые файлы. В ваш основной проект, который опирается на статическую библиотеку, вы также должны включить этот пакет. Ваш основной проект теперь будет иметь доступ к файлу мама, который необходим для использования основных данных.

Чтобы использовать базовые данные с мамой из пакета, вы должны создать в своем коде объединенную управляемую объектную модель (возможно, основной проект также имеет некоторую базовую модель данных):


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


Если вы просто включите комплект, вам не придется выдавать xcdatamodel, необходимо включить только скомпилированный файл мамы.

2 голосов
/ 31 июля 2014

Ответ Prairiedogg немного устарел, вот руководство по выполнению этого в Xcode 5: http://bharathnagarajrao.wordpress.com/2014/02/14/working-with-core-data-in-a-static-library/

2 голосов
/ 28 февраля 2012

Решение Sascha Konietzke работает хорошо, но для его работы необходимо предоставить одно важное предупреждение. Пакет, содержащий модель, должен быть загружен первым, иначе он не будет включен в массив и объединен в MOM.

В его случае он, вероятно, уже получил доступ к ресурсам из пакета, поэтому пакет уже был загружен до выполнения этого кода.

2 голосов
/ 02 декабря 2011

У меня тоже есть библиотека с coredata. я нашел этот шаблон для управления фреймворком с помощью ресурсов для вставки

это действительно просто использовать в новом проекте (сложнее применить в существующем) но для фреймворков, это действительно круто: -)

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

2 голосов
/ 11 ноября 2009

Нет, ограничение на использование фреймворков сторонних разработчиков в приложении для iPhone действительно меняет игру зависимостей по сравнению с OS X. Большинство «фреймворков» для iPhone (например, набор инструментов Google для Mac, Core Plot и т. Д.) Фактически рекомендуют что вы включаете источник в основной проект приложения, а не связываете продукт (т. Е. Статическую библиотеку). Я думаю, что сообщество согласилось с тем, что на iPhone вполне нормально ожидать, что потребители вашей платформы должны будут выполнить небольшую «ручную» работу, чтобы использовать вашу библиотеку. В вашем случае это включает файл xcdatamodel в основной проект. Как и в большинстве Objective-C, скажите своим пользователям не использовать детали реализации и оставьте все как есть.

1 голос
/ 09 октября 2017

Обратите внимание, что вместо использования файла xcdatamodel / mom вы также можете создать свою модель в коде (особенно если у вас простая модель), и таким образом вам не нужно будет создавать дополнительный пакет для ресурсов. Вот простой пример с одной таблицей, которая содержит два атрибута:

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

Вот учебник по созданию модели из кода: https://www.cocoanetics.com/2012/04/creating-a-coredata-model-in-code/

Также на основе этого подхода я создал небольшую и простую в использовании библиотеку, которая может соответствовать вашим потребностям, под названием LSMiniDB , чтобы вы также могли проверить ее.

0 голосов
/ 26 ноября 2015

Версия Swift 2 для ответа Саши:

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!
}()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...