由于 NSSQLiteErrorDomain = 1032,iOS 核心数据 saveContext 方法不成功

标签 ios objective-c sqlite core-data concurrency

这个问题的一些背景,我试图包括我认为可能相关的内容以帮助理解上下文。

我目前正在添加一个链接库,它使用核心数据来保存一些用户信息,以及一个将实体添加到应用程序中已有的核心数据模型的功能。每个 managedObjectContext 在创建(验证)时都有自己的实例以及自己的 PSC 和 MOM,并且都不与其他实体交互(因此看起来是独立的)。

以下全部代码、错误和(我认为是问题)都在应用程序的主要目标中。 (希望)不是新添加的链接库。

saveContext 方法是:

- (void)saveContext {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSError *error = nil;
        // Register
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myManagedObjectContextDidSaveNotificationHandler:) name:NSManagedObjectContextDidSaveNotification object:self.managedObjectContext];

        if (self.managedObjectContext != nil) {
            if ([self.managedObjectContext hasChanges]) {
                BOOL success = [self.managedObjectContext save:&error];
                if (!success) {
                    [Error showErrorByAppendingString:NSLocalizedString(@"UnableToSaveChanges", nil) withError:error];
                } else {
                     // 
                }
            }
        }
        // Unregister
        [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification    object:self.managedObjectContext];
    });  
}

调用时,error = nil,success = NO,通过强制编译器排除异常,我得到以下信息:

CoreData: error: exception during obtainPermenantIDsForObjects: Updating max pk failed: attempt to write a readonly database with userInfo of { NSSQLiteErrorDomain = 1032; }

我用谷歌搜索了“NSSQLiteErrorDomain = 1032”、“obtainPermenantIDsForObjects”和“CoreData 只读数据库”。看起来每个对象的关键主键是相同的,但我正在设置该值,我相信 sqlite 是。我还没有找到任何解决方案来帮助解决这个问题。我确实在启动时传递了参数,“Concurrency Debug 1”设置为打开。

我没有实现 obtainPermenantIDsForObjects 并且我搜索了整个项目但找不到它的实现所以我认为 CoreData 正在使用它。

在主队列上调用了 saveContext 方法,因为那是我的前辈们推出代码的方式,而我现在没有时间处理它。

调用 saveContext 的方法(从后台线程):

- (NSMutableArray *)convertRawStepDataTo:(NSMutableArray*)steps
                           withDates:(NSMutableArray*)dates
              inManagedObjectContext:(NSManagedObjectContext*)theMOC {

    NSMutableArray *theStepsArray = [[NSMutableArray alloc] init];

    // prepare values for chart
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    StepSelector *theSelector = [[StepSelector alloc] init];
    NSString* apiSelectionForStep = [theSelector getCurrentSelectionString];

    for (int iter = 0; iter < steps.count; iter++) {
        NSNumber *currStepValue = [steps objectAtIndex:iter];
        // NSNumber *stepCountforIter = [NSNumber numberWithLong:[[steps objectAtIndex:iter] longValue]];

        NSNumber* dateForIter = [NSNumber numberWithLong:[[dates objectAtIndex:iter] longLongValue]];
        Step *step = [delegate addStepObjectToPersistentStorewithAPI:apiSelectionForStep
                                                         andStep:stepCountforIter
                                                         andDate:dateForIter
                                                          forMOC:theMOC];

        [theStepsArray addObject:step];

        if (VERBOSE) {
            NSLog(@"This is step number %d, with object ID: %@", count, [theMOC objectWithID:step.objectID]);
            count++;
        }
    }
    [delegate saveContext];
    return theStepsArray;
}

这就是我认为可能有帮助的所有内容。主要目标中 MOC 的源是 appDelegate,它是所有核心数据代码最初编写的地方。

编辑 这是请求的 PSC 代码。该商店位于文档目录中。我发现这些对象正在保存到持久存储中。但错误仍然存​​在。请在下方查看 PSC 代码:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }

    NSURL *storeUrl = [self getStoreURL];

    // Rollback journalling mode...
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES],NSInferMappingModelAutomaticallyOption,
                             NSFileProtectionComplete, NSFileProtectionKey,
                             @{@"journal_mode": @"TRUNCATE"}, NSSQLitePragmasOption, nil];

    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

    NSError *error = nil;
    self.persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error];
    if (!self.persistentStore) {
        NSLog(@"Error: %@",error);
        [Error showErrorByAppendingString:NSLocalizedString(@"UnableToFindDatabaseFile", nil) withError:error];
    }

    return persistentStoreCoordinator;
}

-(NSURL *)getStoreURL {
    NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: kSQLFILENAME];
    /*
     Set up the store.
     For the sake of illustration, provide a pre-populated default store.
     */
    NSFileManager *fileManager = [NSFileManager defaultManager];
    // If the expected store doesn't exist, copy the default store.
    if (![fileManager fileExistsAtPath:storePath]) {
        NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:SQLFILEPATHRESOURCE ofType:@"sqlite"];
        if (defaultStorePath) {
            [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
        }
    }

    NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

    return storeUrl;
}

最佳答案

NSSQLiteErrorDomain 键意味着这个错误来自 SQLite,并且 Core Data 将它传回给你。 SQLite defines error 1032 as follows :

The SQLITE_READONLY_DBMOVED error code is an extended error code for SQLITE_READONLY. The SQLITE_READONLY_DBMOVED error code indicates that a database cannot be modified because the database file has been moved since it was opened, and so any attempt to modify the database might result in database corruption if the processes crashes because the rollback journal would not be correctly named.

...这似乎意味着 SQLite 将持久性存储文件设置为只读,因为自打开以来它发生了一些事情,并且 SQLite 试图防止数据损坏。

我在您发布的代码中没有看到任何明显错误,至少就错误代码描述而言是这样。所以我想知道,您是否在其他任何地方做任何会直接影响持久存储文件的事情(即以任何方式触摸文件而不是通过核心数据提取/保存调用)?

错误码描述中提到的回滚日志让我想知道将journal_mode设置为TRUNCATE是否相关。如果是我,我会删除它(我不知道它在这里打算完成什么)或将它设置为 DELETE。无论如何,至少出于测试目的,希望能更好地理解问题。

关于由于 NSSQLiteErrorDomain = 1032,iOS 核心数据 saveContext 方法不成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39155955/

相关文章:

ios - AVPlayerLayer 动画帧变化

ios - Objective-C绘制图像

ios - Sqlite3 中 ALTER TABLE ADD COLUMN 的速度?

SQL - 从每个表中选择最大值,按所述最大值排序,然后按 created_at

iphone - MKAnnotationView 自定义图像未显示

javascript - Sequelize sqlite3连接到数据库但在获取数据时抛出错误

iphone - UIActivityViewController - 检测发送错误与取消错误

ios - UIApplication实例失败

iphone - 在应用程序运行时阻止 Iphone iOS 中的调用和短信

objective-c - 如何禁用 iPhone 模拟器应用程序的位置服务?