Подтвердить что ты не робот

Основные данные в статической библиотеке для iPhone

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

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

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

4b9b3361

Ответ 1

Я также создал свою собственную статическую библиотеку, которая использует 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

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

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

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

  • Создайте новый объект сборки типа Loadable Bundle, найденный под MacOS X > Cocoa, позвоните в новый Target MyStaticLibraryModels.

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

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

  • MyAwesomeApp использует CoreData, имеет собственный файл .xcdatamodel, который будет скомпилирован в файл .mom во время собственного процесса сборки. Мы хотим объединить этот файл .mom с тем, который мы импортировали в MyStaticLibraryModels.bundle. Где-то в проекте MyAwesomeApp существует метод, который возвращает MyAwesomeApp 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 и 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 из MyAwesomeApp и MyStaticLibrary.

Ответ 3

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

Ответ 4

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

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

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

Ответ 5

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

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

Ответ 7

Версия Swift 2 для ответа 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!
}()

Ответ 8

Обратите внимание, что вместо использования файла 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, чтобы вы могли проверить это также.