由于 NSSQLiteErrorDomain = 1032,iOS Core Data saveContext 方法不成功

Posted

技术标签:

【中文标题】由于 NSSQLiteErrorDomain = 1032,iOS Core Data saveContext 方法不成功【英文标题】:iOS Core Data saveContext method is unsuccessful due to NSSQLiteErrorDomain = 1032 【发布时间】:2016-08-25 22:54:33 【问题描述】:

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

我目前正在添加一个链接库,它使用 Core Data 来保存一些用户信息,以及一个将实体添加到应用程序中已经存在的 Core Data 模型的功能。每个 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:错误:在 gainPermenantIDsForObjects 期间出现异常:更新最大 pk 失败:尝试使用 NSSQLiteErrorDomain = 1032; 的 userInfo 写入只读数据库;

我用谷歌搜索了“NSSQLiteErrorDomain = 1032”、“obtainPermenantIDsForObjects”和“CoreData 只读数据库”。似乎每个对象的键主键是相同的,但我正在设置该值,我相信 sqlite 是。我还没有找到任何解决方案来帮助解决这个问题。我确实在启动时传递了参数,“并发调试 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,这是最初编写所有核心数据代码的地方。

EDIT 这是请求的 PSC 代码。该存储位于文档目录中。我发现这些对象正在保存到 Persistent Store.. 但错误仍然存​​在。以下为 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;

【问题讨论】:

你是如何创建持久存储的,SQLite 文件的位置是什么? @Wain 更新了问题并回复了您的问题。希望这会让它更清楚。 【参考方案1】:

NSSQLiteErrorDomain 键表示此错误来自 SQLite,并且 Core Data 正在将其传回给您。 SQLite defines error 1032 as follows:

SQLITE_READONLY_DBMOVED 错误代码是 SQLITE_READONLY 的扩展错误代码。 SQLITE_READONLY_DBMOVED 错误代码表示无法修改数据库,因为数据库文件自打开后已被移动,因此如果进程因回滚日志未正确命名而崩溃,则任何修改数据库的尝试都可能导致数据库损坏。

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

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

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

【讨论】:

汤姆,谢谢!因此,将 journal_mode 设置为“DELETE”解决了这个问题。我在您的回答之后删除了该选项,这似乎已经解决了这个问题,但是当时我添加到数据库中的新实体只有在我保存了在我的功能之前存在于 MOM 中的实体时才会持续存在。我认为问题已经解决了,这是我正在做的其他事情,但今天我添加了选项并将其设置为 DELETE,这似乎做到了。谢谢!现在来研究为什么...

以上是关于由于 NSSQLiteErrorDomain = 1032,iOS Core Data saveContext 方法不成功的主要内容,如果未能解决你的问题,请参考以下文章

NSPersistentStoreCoordinator 在尝试访问 sqlite 文件时引发错误 NSSQLiteErrorDomain=26

iOS:核心数据和磁盘空间

Collect failed in ... s 由于 Stage 由于 SparkContext 已关闭而取消

由于计算机积极拒绝

由于目标计算机积极拒绝,无法连接。

我在Android Studio工作,由于系统崩溃,一个或多个功能由于频繁的系统崩溃而崩溃。我应该如何恢复它?