Любой способ предварительно заполнить основные данные?
Я создаю список приложений и резервное копирование его с основными данными.
Я хотел бы иметь список по умолчанию, скажем, 10 пунктов аэропорта, так что пользователю не придется начинать с нуля.
есть ли способ сделать это?
любая помощь приветствуется. Спасибо заранее.
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"];