Как вынудить coredata восстановить sqlite модель базы данных?

В моем приложении я иногда должен восстанавливать и повторно заполнять файл базы данных. SQLite databse создается и управляется стеком CoreData.

То, что я пытаюсь сделать, отбросить файл и затем затем воссоздать объект persistentStoreCoordinator.

Это работает под средством моделирования, но не на устройстве, где я получаю такую ошибку:

NSFilePath = "/var/mobile/Applications/936C6CC7-423A-46F4-ADC0-7184EAB0CADD/Documents/MYDB.sqlite";
NSUnderlyingException = I/O error for database at /var/mobile/Applications/936C6CC7-423A-46F4-ADC0-7184EAB0CADD/Documents/MYDB.sqlite.  SQLite error code:1, 'table ZXXXX already exists';

Я не могу найти причину этого всегда. Это указывает на две различных проблемы - ошибка Какао 256 указывает, что файл не существует или не читаем. Но файл создается после создания persistenStoreCoordinator, хотя это пусто, но после выполнения некоторых запросов это исчезает.

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

Я вполне смущен и не могу понять, что продолжается здесь. Мой код похож на это:

NSString *path = [[WLLocalService dataStorePath] relativePath];
NSError *error = nil;

WLLOG(@"About to remove file %@", path);

[[NSFileManager defaultManager] removeItemAtPath: path error: &error];

if (error != nil) {
 WLLOG(@"Error removing the DB: %@", error);
}


[self persistentStoreCoordinator];

WLLOG(@"Rebuild DB result %d", [[NSFileManager defaultManager] fileExistsAtPath: path]);

После того, как этот код является exectued, файл DB существует, но пуст. Когда тогда первый запрос (и все после) выполняется, он дает мне, ошибка выше и файл исчезают.

У кого-либо есть идея что случилось с ним?

Большое спасибо за указание на меня правильный путь!

11
задан Burt 1 March 2010 в 15:50
поделиться

3 ответа

Стек Core Data не любит, когда вы удаляете находящийся под ним файл. Если вы хотите удалить файл, вы должны разорвать стек, удалить файл и затем восстановить стек. Это устранит проблему.

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

Вы можете попробовать сообщить NSPersistentStoreCoordinator , что вы удаляете файл с помощью вызова -removePersistentStore: error: , а затем добавляете новое хранилище с помощью вызова -addPersistentStoreWithType : конфигурация: URL: параметры: ошибка: . Я делаю это сейчас в ZSync, и он отлично работает.

18
ответ дан 3 December 2019 в 03:35
поделиться

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

Вот код из приложения, которое делает что-то подобное (хотя эта версия не будет копировать существующие базы данных):

// Check for the existence of the seed database
// Get the path to the documents directory and append the databaseName
NSString* databasePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: kDatabaseName];

NSFileManager* fileManager = [NSFileManager defaultManager];
if ( ![fileManager fileExistsAtPath: databasePath] ) 
{
    NSString* databasePathFromApp = [[[NSBundle mainBundle] resourcePath] 
                                     stringByAppendingPathComponent: kDatabaseName];

    [fileManager copyItemAtPath: databasePathFromApp 
                         toPath: databasePath 
                          error: nil];
}
[fileManager release];
1
ответ дан 3 December 2019 в 03:35
поделиться

Я использую следующий метод -resetApplicationModel в моем делегате приложения, и он отлично работает для меня.

Возможно, вам не понадобится пользовательское значение по умолчанию kApplicationIsFirstTimeRunKey , но я использую его, чтобы проверить, нужно ли заполнять хранилище основных данных настройками по умолчанию с помощью специального метода под названием -setupModelDefaults , который я также вызовите из -applicationDidFinishLaunching: , если флаг первого запуска - YES .

- (BOOL) resetApplicationModel {

    // ----------------------
    // This method removes all traces of the Core Data store and then resets the application defaults
    // ----------------------

    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:kApplicationIsFirstTimeRunKey];
    NSLog(@"Turned ON the first-time run flag...");

    NSError *_error = nil;
    NSURL *_storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"MyAppSQLStore.sqlite"]];
    NSPersistentStore *_store = [persistentStoreCoordinator persistentStoreForURL:_storeURL];

    //
    // Remove the SQL store and the file associated with it
    //
    if ([persistentStoreCoordinator removePersistentStore:_store error:&_error]) {
        [[NSFileManager defaultManager] removeItemAtPath:_storeURL.path error:&_error];
    }

    if (_error) {
        NSLog(@"Failed to remove persistent store: %@", [_error localizedDescription]);
        NSArray *_detailedErrors = [[_error userInfo] objectForKey:NSDetailedErrorsKey];
        if (_detailedErrors != nil && [_detailedErrors count] > 0) {
            for (NSError *_detailedError in _detailedErrors) {
                NSLog(@" DetailedError: %@", [_detailedError userInfo]);
            }                
        }
        else {
            NSLog(@" %@", [_error userInfo]);
        }
        return NO;
    }

    [persistentStoreCoordinator release], persistentStoreCoordinator = nil;
    [managedObjectContext release], managedObjectContext = nil;

    //
    // Rebuild the application's managed object context
    //
    [self managedObjectContext];

    //
    // Repopulate Core Data defaults
    //
    [self setupModelDefaults];

    return YES;
}
8
ответ дан 3 December 2019 в 03:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: