Любой способ предварительно заполнить основные данные? - PullRequest
61 голосов
/ 09 февраля 2010

Я создавал приложение со списком и подкреплял его основными данными.

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

Есть ли способ сделать это?

Любая помощь приветствуется. Заранее спасибо.

Ответы [ 9 ]

58 голосов
/ 10 февраля 2010

Вот лучший способ (и не требует знаний SQL):
Создайте быстрое приложение Core Data для iPhone (или даже приложение Mac), используя ту же объектную модель, что и приложение List. Напишите несколько строк кода, чтобы сохранить управляемые объекты по умолчанию, которые вы хотите хранить. Затем запустите это приложение в симуляторе. Теперь перейдите в ~ / Библиотека / Поддержка приложений / iPhone Simulator / Пользователь / Приложения. Найдите ваше приложение среди идентификаторов GUID, а затем просто скопируйте хранилище sqlite в папку проекта вашего приложения List.

Затем загрузите это хранилище, как в примере с CoreDataBooks.

30 голосов
/ 09 февраля 2010

Да, на самом деле пример CoreDataBooks делает это, вы можете скачать код здесь: пример кода

Что вы делаете, это создаете внутреннее хранилище (базу данных), используя обычную процедуру для инициализации вашего хранилища, как если бы вы работали с любым другим хранилищем, затем вы просто запускаете свой код и позволяете ему выполнять код, как описано в примере CoreDataBooks ( фрагмент кода ниже). Как только хранилище будет инициализировано, вы захотите создать NSManagedObjectContext и инициализировать его с созданным постоянным хранилищем, вставить все нужные вам сущности и сохранить контекст.

Как только контекст успешно сохранен, вы можете остановить свое приложение, затем перейти к поиску и перейти в папку: ~/Library/Developer введите поиск .sqlite и посмотрите в / Developer, сортировка по дате даст вам самые последние База данных .sqlite, которая должна соответствовать времени выполнения кода, затем вы можете взять это хранилище и добавить его в качестве ресурса вашего проекта. Этот файл затем может быть прочитан постоянным координатором хранилища.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator) {
    return persistentStoreCoordinator;
}


NSString *storePath = [[self applicationDocumentsDirectory]      stringByAppendingPathComponent: @"CoreDataBooks.sqlite"];
 /*
  Set up the store.
 For the sake of illustration, provide a pre-populated default store.
 */
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
  NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataBooks"      ofType:@"sqlite"];
 if (defaultStorePath) {
 [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
 }
}

NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber   numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

 NSError *error;
 if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
  // Update to handle the error appropriately.
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 exit(-1);  // Fail
}    

return persistentStoreCoordinator;
}

Надеюсь, это поможет.

-Oscar

11 голосов
/ 31 мая 2013

С этим методом вам не нужно создавать отдельное приложение или иметь какие-либо знания SQL. Вам нужно только создать файл JSON для исходных данных.

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

Чтобы прочитать файл json в объекты:

NSString *initialDataFile = [[NSBundle mainBundle] pathForResource:@"InitialData" ofType:@"json"];
NSError *readJsonError = nil;
NSArray *initialData = [NSJSONSerialization
                        JSONObjectWithData:[NSData dataWithContentsOfFile:initialDataFile]
                        options:kNilOptions
                        error:&readJsonError];

if(!initialData) {
    NSLog(@"Could not read JSON file: %@", readJsonError);
    abort();
}

Тогда вы можете сделать для него объекты-сущности так:

[initialData enumerateObjectsUsingBlock:^(id objData, NSUInteger idx, BOOL *stop) {

    MyEntityObject *obj = [NSEntityDescription
                          insertNewObjectForEntityForName:@"MyEntity"
                          inManagedObjectContext:dataController.managedObjectContext];

    obj.name = [objData objectForKey:@"name"];
    obj.description = [objData objectForKey:@"description"];

    // then insert 'obj' into Core Data

}];

Если вы хотите более подробное описание того, как это сделать, ознакомьтесь с этим руководством: http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated

8 голосов
/ 09 февраля 2010

Для 10 элементов вы можете просто сделать это в пределах applicationDidFinishLaunching: в вашем делегате приложения.

Определите метод, скажем, insertPredefinedObjects, который создает и заполняет экземпляры объекта, отвечающего за управление элементами вашего аэропорта, и сохраняет ваш контекст. Вы можете либо прочитать атрибуты из файла, либо просто встроить их в свой код. Затем вызовите этот метод внутри applicationDidFinishLaunching:.

5 голосов
/ 19 ноября 2012

Помните, что, следуя примеру кода CoreDataBooks, он, вероятно, нарушает Рекомендации по хранению данных iOS:

https://developer.apple.com/icloud/documentation/data-storage/

Мне было отказано в приложении для копирования предварительно заполненной базы данных (только для чтения) в каталог документов, поскольку она затем копируется в iCloud, и Apple хочет, чтобы это происходило только с пользовательскими файлами. 1006 *

Приведенные выше рекомендации предлагают некоторые решения, но в основном сводятся к:

  • хранит БД в каталоге caches и корректно обрабатывает ситуации, когда ОС очищает кеши - вам придется перестраивать БД, что, вероятно, исключает ее для большинства из нас.

  • установить «не кэшировать атрибут» в файле БД, что немного загадочно, поскольку это необходимо сделать по-разному для разных версий ОС.

Я не думаю, что это слишком сложно, но учтите, что у вас есть кое-что еще, чтобы этот пример кода работал вместе с iCloud ...

2 голосов
/ 21 августа 2015

Этот ответ только для людей, которые

  • включая предварительно заполненную базу данных в вашем приложении
  • создание приложения для нескольких платформ (iOS, Android и т. Д.)

Я создал предварительно заполненную базу данных SQLite для приложения Android. Затем, когда я делал версию приложения для iOS, я подумал, что будет лучше использовать Core Data. Поэтому я потратил довольно много времени на изучение Core Data, а затем переписал код, чтобы заранее заполнить базу данных. Изучение того, как выполнять каждый шаг на обеих платформах, требовало много исследований, проб и ошибок. Было намного меньше совпадений, чем я бы надеялся.

В итоге я просто решил использовать ту же базу данных SQLite из моего проекта Android. Затем я использовал оболочку FMDB для прямого доступа к базе данных в iOS. Преимущества:

  • Нужно сделать предварительно заполненную базу данных только один раз.
  • Не требует смены парадигмы. Синтаксис между Android и FMDB, хотя и отличается, все еще довольно похож.
  • Иметь гораздо больше контроля над выполнением запросов.
  • Разрешает полнотекстовый поиск.

Хотя я не сожалею об изучении Core Data, если бы я делал это заново, я мог бы сэкономить много времени, просто придерживаясь SQLite.

Если вы начинаете в iOS, а затем планируете перейти на Android, я бы все равно использовал оболочку SQLite, такую ​​как FMDB, или какое-либо другое программное обеспечение для предварительного заполнения базы данных. Хотя технически вы можете извлечь базу данных SQLite, предварительно заполненную данными ядра, схема (имена таблиц и столбцов и т. Д.) Будет иметь странное имя.

Кстати, если вам не нужно изменять предварительно заполненную базу данных, не копируйте ее в каталог документов после установки приложения. Просто получите к нему доступ прямо из комплекта.

// get url reference to databaseName.sqlite in the bundle
let databaseURL: NSURL = NSBundle.mainBundle().URLForResource("databaseName", withExtension: "sqlite")!

// convert the url to a path so that FMDB can use it
let database = FMDatabase(path: databaseURL.path)

Это позволяет вам не иметь двух копий.

Обновление

Теперь я использую SQLite.swift вместо FMDB, потому что он лучше интегрируется с проектами Swift.

2 голосов
/ 14 января 2015

Как насчет проверки, существуют ли какие-либо объекты, а если нет, создать объект с некоторыми данными?

NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Settings"];
_managedObjectSettings = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];

if ([_managedObjectSettings count] == 0) {
    // first time, create some defaults
    NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:@"Settings" inManagedObjectContext:managedObjectContext];

    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"speed"];
    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"sound"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey:@"aspect"];
    [newDevice setValue:[NSNumber numberWithBool: NO  ] forKey: @"useH264"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey: @"useThumbnail"];

    NSError *error = nil;
    // Save the object to persistent store
    if (![managedObjectContext save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
}
2 голосов
/ 01 ноября 2013

Итак, я разработал универсальный метод, который загружается из словаря (возможно из JSON) и заполняет базу данных. Он должен использоваться ТОЛЬКО с доверенными данными (из безопасного канала), он не может обрабатывать циклические ссылки, и перенос схем может быть проблематичным ... Но для простых случаев использования, таких как мой, это должно быть хорошо

Вот, пожалуйста,

- (void)populateDBWithDict:(NSDictionary*)dict
               withContext:(NSManagedObjectContext*)context
{
    for (NSString* entitieName in dict) {

        for (NSDictionary* objDict in dict[entitieName]) {

            NSManagedObject* obj = [NSEntityDescription insertNewObjectForEntityForName:entitieName inManagedObjectContext:context];
            for (NSString* fieldName in objDict) {

                NSString* attName, *relatedClass, *relatedClassKey;

                if ([fieldName rangeOfString:@">"].location == NSNotFound) {
                    //Normal attribute
                    attName = fieldName; relatedClass=nil; relatedClassKey=nil;
                } else {
                    NSArray* strComponents = [fieldName componentsSeparatedByString:@">"];
                    attName = (NSString*)strComponents[0];
                    relatedClass = (NSString*)strComponents[1];
                    relatedClassKey = (NSString*)strComponents[2];
                }
                SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", attName ]);
                NSMethodSignature* signature = [obj methodSignatureForSelector:selector];
                NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
                [invocation setTarget:obj];
                [invocation setSelector:selector];

                //Lets set the argument
                if (relatedClass) {
                    //It is a relationship
                    //Fetch the object
                    NSFetchRequest* query = [NSFetchRequest fetchRequestWithEntityName:relatedClass];
                    query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:relatedClassKey ascending:YES]];
                    query.predicate = [NSPredicate predicateWithFormat:@"%K = %@", relatedClassKey, objDict[fieldName]];

                    NSError* error = nil;
                    NSArray* matches = [context executeFetchRequest:query error:&error];


                    if ([matches count] == 1) {
                        NSManagedObject* relatedObject = [matches lastObject];
                        [invocation setArgument:&relatedObject atIndex:2];
                    } else {
                        NSLog(@"Error! %@ = %@ (count: %d)", relatedClassKey,objDict[fieldName],[matches count]);
                    }


                } else if ([objDict[fieldName] isKindOfClass:[NSString class]]) {

                    //It is NSString
                    NSString* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];
                } else if ([objDict[fieldName] isKindOfClass:[NSNumber class]]) {

                    //It is NSNumber, get the type
                    NSNumber* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];

                }
                [invocation invoke];


            }

            NSError *error;
            if (![context save:&error]) {
                NSLog(@"%@",[error description]);
            }
        }
    }   
}

И загружает из JSON ...

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"initialDB" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];

NSError* error;
NSDictionary *initialDBDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                           options:NSJSONReadingMutableContainers error:&error];

[ self populateDBWithDict:initialDBDict withContext: [self managedObjectContext]];

Примеры JSON

    {
    "EntitieA": [ {"Att1": 1 }, {"Att1": 2} ],
    "EntitieB": [ {"Easy":"AS ABC", "Aref>EntitieA>Att1": 1} ]
    }

и

{
    "Country": [{"Code": 55, "Name": "Brasil","Acronym": "BR"}],
    "Region": [{"Country>Country>code": 55, "Code": 11, "Name": "Sao Paulo"},
               {"Country>Country>code": 55, "Code": 31, "Name": "Belo Horizonte"}]
}
0 голосов
/ 25 марта 2013

Другой способ хранения значений по умолчанию находится в NSUserDefaults. (Сюрприз!) И это легко.

По предложению некоторых, поместите это в applicationDidFinishLaunching

В данном случае 10 значений по умолчанию, Airport0 - 9

Настройка

NSUserDefaults *nud = [NSUserDefaults standardUserDefaults];
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport0"];
    ...
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport9"];
[nud synchronize];

или

[[NSUserDefaults standardUserDefaults] setString:@"MACADDRESSORWHY" forKey:@"Airport9"]];
     ...
[[NSUserDefaults standardUserDefaults] synchronize];

И затем, получение значений по умолчанию.

NSString *air0 = [[NSUserDefaults standardUserDefaults] stringForKey:@"Airport0"];
...