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


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

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

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

любая помощь приветствуется. Спасибо заранее.

9 58

9 ответов:

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

затем загрузите это хранилище, как они делают в Примере CoreDataBooks.

Да есть на самом деле пример 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;
}

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

-Оскар

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

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

для чтения 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

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

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

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

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

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

руководство выше некоторых решений, но они в основном сводятся к:

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

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

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

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

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

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]);
    }
}

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

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

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

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

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

хотя я не жалею об изучении основных данных, если бы я сделал это снова, я мог бы сэкономить много времени, просто придерживаясь 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.Свифт а не FMDB, потому что он лучше интегрируется с проектами Swift.

другой способ хранения значений по умолчанию находится с помощью 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"];