gpt4 book ai didi

ios - NSManagedObjectContext 没有正确保存到 SQLite

转载 作者:行者123 更新时间:2023-11-28 19:05:38 24 4
gpt4 key购买 nike

所以,

我在使用 Core Data 和尝试将数据正确保存到 SQLite 数据库时遇到问题。

我有两个“应用程序”:一个用于加载 SQLite 数据(我们称之为“Loader.App”),另一个用于显示数据(“Display.App”)。加载程序只是基于 Web 的 CMS 和需要 SQLite 数据库(同样由 Core Data 加载)的应用程序之间的便利“桥梁”。

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

奇怪的是,如果我在阅读器 (Base.App) 中打开 SQLite DB 文件并对数据库进行 VACUUM,它会完美地加载到 Display.App 中。根据 Python 文件 io 的经验,我知道如果你没有正确关闭文件,数据就不会从 io 缓冲区写入文件。显然,数据正在写入 SQLite 文件(因此我可以用阅读器 (Base.App) 打开它)。但这让我想知道是否有我没有调用的文件关闭方法?

基本上...

方法一:

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

结果:MyAppDB.sqlite 中没有数据

方法二:

  1. 运行 Loader.App
  2. 用阅读器(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 上,Core Data 通常在 WAL(预写日志记录)模式下使用 SQLite。这意味着除了 MyAppDB.sqlite 之外,还有名为 MyAppDB.sqlite-walMyAppDB.sqlite-shm 的文件。这些文件至关重要。如果您只复制 SQLite 文件而不复制日志,您将丢失数据(如您所见)。

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

您有几个不同的选择:

  • 最简单的方法是复制所有文件。问题已解决。
  • 另一种选择是更改加载器应用中的日志模式,以避免复制更多文件的需要。您可以通过在添加持久存储时传递一个额外的选项来做到这一点:

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

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

关于ios - NSManagedObjectContext 没有正确保存到 SQLite,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20687547/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com