it-roy-ru.com

Любой способ предварительно заполнить основные данные?

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

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

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

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

60
Tanner

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

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

58
Ken Aspeslagh

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

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

Как только контекст успешно сохранен, вы можете остановить свое приложение, затем перейти в Finder и перейти в папку: ~/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;
}

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

-Оскар

30
Oscar Gomez

С этим методом вам не нужно создавать отдельное приложение или иметь какие-либо знания 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 обновлено

11
gitaarik

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

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

8
Massimo Cafaro

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

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

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

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

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

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

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

4
Adrian Bigland

Поэтому я разработал общий метод, который загружается из словаря (возможно из 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"}]
}
2
Felizardo

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

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
Md1079

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

  • включая предварительно заполненную базу данных в вашем приложении
  • создание приложения для нескольких платформ (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
Suragch

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

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

В данном случае 10 значений по умолчанию, Аэропорт0 через 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"];
0
Gabe Rainbow