NSManagedObjectContext没有正确保存到SQLite

所以,

我有一个核心数据的问题,并试图将数据正确保存到SQLite数据库。

我有两个“应用程序”:一个用于加载SQLite数据(让我们称之为“Loader.App”),另一个用于显示数据(“Display.App”)。 加载器只是一个基于Web的CMS(它将数据导出为JSON数据)和需要SQLite DB(再次由Core Data加载)的App之间的一个“桥梁”。

当我在Loader.App中保存上下文时,它将数据保存到SQLite文件中。 我可以在SQLite阅读器(如Base.App)中打开此文件,并显示所有的数据。 问题是:当我将该SQLite文件带到Display.App时,它会将该文件复制到文档目录中,但其中没有任何数据。 但是,它具有所有正确的表格 – 就像加载数据之前的SQLite文件一样。

奇怪的是,如果我打开阅读器(Base.App)中的SQLite数据库文件和VACUUM数据库,它加载在Display.App完全罚款 。 从Python中的文件io的经验,我知道,如果你没有正确closures文件,数据不会写入从io缓冲区的文件。 显然,数据正在写入SQLite文件(因此我可以用一个阅读器(Base.App)打开它)。 但它让我怀疑是否有一个文件closures方法,我不打电话?

基本上…

方法1:

  1. 运行Loader.App
  2. 将MyAppDB.sqlite复制到Display.App
  3. 运行Display.App

结果 :MyAppDB.sqlite里面没有数据

方法2:

  1. 运行Loader.App
  2. 使用reader(Base.App)打开MyAppDB.sqlite
  3. 真空
  4. 将MyAppDB.sqlite复制到Display.App
  5. 运行Display.App

结果 :MyAppDB.sqlite包含数据,我们很高兴。

这里是我的Loader.App的修剪版本:

int main(int argc, const char * argv[]) { @autoreleasepool { // Create the managed object context NSManagedObjectContext *context = managedObjectContext(); // Custom code here... importDataEntriesFromJSON(context); // Save the managed object context NSError *error = nil; if (![context save:&error]) { NSLog(@"Error while saving %@", ([error localizedDescription] != nil) ? [error localizedDescription] : @"Unknown Error"); exit(1); } } return 0; } static NSManagedObjectModel *managedObjectModel() { static NSManagedObjectModel *model = nil; if (model != nil) { return model; } NSString *path = @"MyAppDB"; path = [path stringByDeletingPathExtension]; NSURL *modelURL = [NSURL fileURLWithPath:[path stringByAppendingPathExtension:@"mom"]]; model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return model; } static NSManagedObjectContext *managedObjectContext() { static NSManagedObjectContext *context = nil; if (context != nil) { return context; } @autoreleasepool { context = [[NSManagedObjectContext alloc] init]; NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel()]; [context setPersistentStoreCoordinator:coordinator]; NSString *STORE_TYPE = NSSQLiteStoreType; NSString *path = @"MyAppDB"; path = [path stringByDeletingPathExtension]; NSURL *url = [NSURL fileURLWithPath:[path stringByAppendingPathExtension:@"sqlite"]]; // Clear old SQLite NSFileManager *manager = [NSFileManager defaultManager]; NSError *error; [manager removeItemAtURL:url error:&error]; //NSError *error; NSPersistentStore *newStore = [coordinator addPersistentStoreWithType:STORE_TYPE configuration:nil URL:url options:nil error:&error]; if (newStore == nil) { NSLog(@"Store Configuration Failure %@", ([error localizedDescription] != nil) ? [error localizedDescription] : @"Unknown Error"); } } return context; } void importDataEntriesFromJSON( NSManagedObjectContext *context ) { NSError* err = nil; NSString* dataPath = [[NSBundle mainBundle] pathForResource:@"data_entries" ofType:@"json"]; NSArray* data_entries = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath] options:kNilOptions error:&err]; NSLog(@"Imported %lu data_entries from JSON", (unsigned long)[data_entries count]); [data_entries enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { DBDataEntry *dataEntry = [NSEntityDescription insertNewObjectForEntityForName:@"DBDataEntry" inManagedObjectContext:context]; dataEntry.data_entry_id = [NSNumber numberWithInt:[[obj objectForKey:@"data_entry_id"] integerValue]]; dataEntry.data_entry_keywords = [obj objectForKey:@"data_entry_keywords"]; dataEntry.data_entry_name = [obj objectForKey:@"data_entry_name"]; NSError *error; if (![context save:&error]) { NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]); } }]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"DBDataEntry" inManagedObjectContext:context]; [fetchRequest setEntity:entity]; NSError *error; NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; for( DBDataEntry *dataEntry in fetchedObjects ) { //NSLog(@"data_entry_id: %@", dataEntry.data_entry_id); //NSLog(@"data_entry_keywords: %@", dataEntry.data_entry_keywords); //NSLog(@"data_entry_name: %@", dataEntry.data_entry_name); NSLog(@"data_entry_id: %@ name: %@", dataEntry.data_entry_id, dataEntry.data_entry_name); } } 

谢谢你的帮助! 🙂

最可能的原因是你正在复制SQLite文件本身而不是它的日志文件。 在iOS 7核心数据通常使用WAL(预写日志logging)模式的SQLite。 这意味着除了MyAppDB.sqlite之外,还有MyAppDB.sqlite名为MyAppDB.sqlite-walMyAppDB.sqlite-shm 。 这些文件至关重要。 如果只复制SQLite文件而不复制日志,则会丢失数据(如您所见)。

在Base.app和vacuum中打开SQLite文件时,日志文件中的所有更改都会滚动到主SQLite文件本身中。 您正在执行额外的步骤,无需复制日记文件。

你有几个不同的select:

  • 简单的方法是复制所有的文件。 问题解决了。
  • 另一种select是在加载器应用程序中更改日记模式,以避免需要复制更多文件。 添加持久性存储时,您可以通过传递额外的选项来完成此操作:

     NSDictionary *options = @{ NSSQLitePragmasOption : @{ @"journal_mode": @"DELETE" } }; 

在调用addPersistentStoreWithType:configuration:URL:options:error:时使用addPersistentStoreWithType:configuration:URL:options:error: