2010-03-01 38 views
10

在我的應用程序中,我有時需要重建和重新填充數據庫文件。 SQLite數據庫由CoreData堆棧創建和管理。如何強制coredata重建sqlite數據庫模型?

我想要做的是放下文件,然後重新創建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後創建的文件IS儘管它是空的,但執行一些查詢後它消失。

表示嘗試創建已存在表的第二條消息在這種情況下很奇怪。

我很困惑,不明白這裏發生了什麼。我的代碼如下所示:

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

執行此代碼後,DB文件存在但爲空。當第一次查詢(以及所有後續)被執行時,它會給我上面的錯誤並且文件消失。

有沒有人知道它有什麼問題?

非常感謝您指點正確的方式!

回答

18

核心數據堆棧不喜歡你在它刪除文件。如果你想刪除文件,你應該拆除堆棧,刪除文件,然後重新構建堆棧。這將消除這個問題。

部分問題是堆棧保留文件中數據的緩存。當您刪除文件時,您無法清除該緩存,然後將核心數據置於未知且不穩定的狀態。

您可以嘗試告訴NSPersistentStoreCoordinator您正在通過調用-removePersistentStore:error:來刪除文件,然後通過調用-addPersistentStoreWithType:configuration:URL:options:error:來添加新的商店。我正在ZSync中執行此操作,並且它工作得很好。

+0

謝謝你的提示,這很有趣,我會嘗試一下。但是,在刪除文件之前發佈NSPersistentStoreCoordinator的所有實例時,是不是這樣?這就是在上面調用我的方法之前發生的事情。我猜想它會刪除並釋放所有後續的數據結構。你能否解釋爲什麼在刪除文件本身之前明確地從協調器中刪除持久存儲是非常重要的? – Burt 2010-03-02 08:18:05

+0

所以我試過你的解決方案,它的工作原理!非常感謝!不過,我仍然想知道明確刪除持久性存儲和簡單釋放協調程序的區別在哪裏。 – Burt 2010-03-02 11:15:37

+1

如果您在'NSManagedObjectContext'中將'NSPersistentStoreCoordinator'設置爲nil並釋放它,那麼您可能會完成同樣的事情,但這遠比指示'NSPersistentStoreCoordinator'去除存儲更重要。 – 2010-03-02 14:32:02

1

您可以將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]; 
8

我在我的應用程序委託中使用以下方法-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; 
} 
+0

嗨@Alex Reynolds,我想重置我的coreData中的所有數據,我想知道,函數[setupModeDefaults]是幹什麼的。還請看看這個http://stackoverflow.com/questions/14646595/ clear-reset-all-coredata-one-to-many-realationship – Ranjit 2013-02-04 07:45:45

+0

這只是一種使用默認值重新填充核心數據存儲的方法。你會編寫自己的方法來恢復默認值。 – 2013-02-04 09:20:42

+0

感謝您的回覆,我試過你的代碼,但它不工作。請你幫我出來 – Ranjit 2013-02-04 09:41:06

相關問題