Обновить NSPersistentStoreCoordinator в AppDelegate из ViewController
У меня есть приложение, в котором PersistentStoreCoordinator настроен в AppDelegate. Я хочу загрузить новую базу данных sqlite из списка сохраненных файлов sqlite. Я счастлив удалить существующий файл Persistent Store и sqlite и заменить файл sqlite файлом, загруженным из таблицы. Однако как перезагрузить / обновить PersistentStoreCoordinator из действия ViewController выбора нового файла? Я попытался установить AppDelegate в качестве делегата ViewController, но это, кажется, создает всевозможные циклические ссылки в приложении. Кроме того, каков точный метод для перезагрузки PersistentStoreCoordinator?
Я пробовал этот код, но он просто очищает постоянное хранилище без обновления загруженным файлом sqlite (Working.sqlite - это имя текущей текущей версии базы данных sqlite):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"];
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSPersistentStore *store = [[delegate.persistentStoreCoordinator persistentStores] lastObject];
NSError *error;
NSPersistentStoreCoordinator *storeCoordinator = delegate.persistentStoreCoordinator;
[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];
NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
NSLog(@"selectedPlan is: %@", loadName);
if (![[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error]) {
NSLog(@"Error: %@", error);
}
else {
[delegate managedObjectContext];
[delegate managedObjectModel];
[delegate persistentStoreCoordinator];
[self.delegate planWasSelectedOnTheFileTableViewController:self];}
ОК - я изменил код, как показано ниже, и когда я выбираю строку для загрузки, у меня теперь происходит сбой при окончательном добавлении нового хранилища в PSC. Коды ошибок равны нулю, поэтому я не уверен, что происходит сбой. NSLogs показывают, что исходное хранилище было удалено, а новая версия скопирована.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"]; AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSPersistentStore *store = [[delegate.persistentStoreCoordinator persistentStores] lastObject];
NSError *error;
NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
NSLog(@"selectedPlan is: %@", loadName);
[delegate.persistentStoreCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");
}
else {NSLog(@"File deleted");}
[[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");
}
else {NSLog(@"path empty");}
NSURL *storeURL = [NSURL fileURLWithPath:targetPath];
error = nil;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
[delegate.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]; { NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self.delegate planWasSelectedOnTheFileTableViewController:self];}
Маркус - я думаю, что это отражает твой совет, но я все еще получаю сбой приложения на этапе addPersistentStore с журналом "неразрешенной ошибки":
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
//setting path to current working sqlite file
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"];
//setting path to selected sqlite file
NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
NSLog(@"selectedPlan is: %@", loadName);
// retrieve the store URL
NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
NSString *storeName = [storeURL absoluteString];
NSLog(@"Persistent Store is: %@", storeName);
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It was there before it was deleted");}
// remove the store
NSError *error;
[delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:&error];
{NSLog(@"Unresolved error on remove %@, %@", error, [error userInfo]);
abort();}
error = nil;
// remove the store file and check it's gone
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");}
else {NSLog(@"File deleted");}
// copy in new file and check it's there
[[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");}
else {NSLog(@"path empty");}
//re-attach the store
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
[delegate.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
{NSLog(@"Unresolved error on add %@, %@", error, [error userInfo]);
abort();}
}
Следуя совету Маркуса, я добавил журнал ошибок в removePersistentStore в измененном коде выше. Проблема возникает в действии удаления. Файл журнала заканчивается следующим образом:
2013-06-01 01: 10: 02.478 inControl [1238: 907] Постоянное хранилище: file: //localhost/var/mobile/Applications/D34C6065-8D59-480F-ABA4-9F10C690F26C/Library/Working.sqlite
2013-06-01 01: 10: 02.481 inControl [1238: 907] Он был там до того, как был удален
2013-06-01 01:10:02.486 inControl[1238:907] Неразрешенная ошибка при удалении (null), (null)
Окончательный рабочий код, следуя советам Маркуса:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
//setting path to current working sqlite file
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"];
//setting path to selected sqlite file
NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
NSLog(@"selectedPlan is: %@", loadName);
// retrieve the store URL
NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
NSString *storeName = [storeURL absoluteString];
NSLog(@"Persistent Store is: %@", storeName);
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It was there before it was deleted");}
// remove the store
NSError *error;
NSPersistentStoreCoordinator *psc = [delegate persistentStoreCoordinator];
NSPersistentStore *ps = [[psc persistentStores] lastObject];
if (![psc removePersistentStore:ps error:&error]) {
NSLog(@"Remove Store Failure: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
} error = nil;
// remove the store file and check it's gone
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");}
else {NSLog(@"File deleted");}
// copy in new file and check it's there
[[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");}
else {NSLog(@"path empty");}
[delegate.managedObjectContext reset];
//re-attach the store
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(@"Add Store Failure: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
}
}
1 ответ
Лучший ответ - сделать -removePersistentStore:error:
на NSPersistentStoreCoordinator
тогда сделай -addPersistentStoreWithType: configuration: configuration URL: options: error:
В рамках этого процесса я бы сделал -reset
на NSManagedObjectContext
а затем опубликовать NSNotification
что ваш контроллер представления слушает, а затем ваш контроллер представления может перезагрузить свои данные.
Вам не нужно удалять любые файлы с диска.
Обновление 1
Во-первых, вы должны сказать нам, что такое авария:)
Во-вторых, вы не используете параметр ошибки на -removePersistentStore...
так что вы можете получить ошибку там.
Обновите вопрос с ошибкой, и это поможет разобраться.
Обновление 2
Этот код не имеет никакого смысла:
// remove the store
NSError *error;
[delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:&error];
{NSLog(@"Unresolved error on remove %@, %@", error, [error userInfo]);
abort();}
error = nil;
Если это верно, то это неправильно. Так должно быть:
NSError *error;
NSPersistentStoreCoordinator *psc = [delegate persistentStoreCoordinator];
NSPersistentStore *ps = [[psc persistentStores] lastObject];
if (![psc removePersistentStore:ps error:&error]) {
NSLog(@"Failure: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
}
Не отвечайте на ошибку, чтобы определить ошибку, проверьте BOOL
это возвращается из звонка.