Core Data在没有明显原因的情况下恢复到以前的状态

时间:2013-05-27 05:38:25

标签: ios core-data

基于Core Data的iOS应用程序的一些客户报告他们偶尔会丢失数据。这些报道非常奇怪,这就是我要求你对此采取行动的原因。客户报告说,当他们在一段时间(几分钟,几小时或第二天)之后重新打开应用程序时,他们的一些数据会丢失,就像底层数据库恢复到以前的状态一样

我已经使用Core Data多年了,之前从未遇到像这样的问题。该应用程序非常简单,这意味着我只使用一个托管对象上下文,并且在应用程序进入后台之前提交更改。

我意识到这是一个很长的过程,但这可能是导致此类问题的一些潜在原因,或者我可以通过哪些检查来收集更多信息?不幸的是,我无法自己重现这个问题,这将使这一切变得更加容易。

更新

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator) return _persistentStoreCoordinator;

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Prime.sqlite"];

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:@{ NSMigratePersistentStoresAutomaticallyOption : @YES, NSInferMappingModelAutomaticallyOption : @YES } error:&error]) {
        // Error Handling
    }

    return _persistentStoreCoordinator;
}

3 个答案:

答案 0 :(得分:2)

检查是否已将保存消息放入相应的appDelegate方法中,以便无法保存而无法重新签名应用程序。 applicationWillResignActive和applicationWillTerminate应该满足您的所有需求。

除此之外,正确的错误处理和日志记录应该会为您带来很多好处。我个人喜欢将这些类型的错误记录到可以根据请求发送给我的文件中。但是对于您的特定应用来说,这可能是过度的。这是从内存中写的,所以原谅任何错误。

NSError *error = nil;
if (![[self managedObjectContext] save:&error])
{
    NSString *errorString = @"%@ ERROR : %@ %@", [[NSDate date] description], [error localizedDescription], [error userInfo]);

    NSString *documentsDirectory = [NSHomeDirectory() 
                                    stringByAppendingPathComponent:@"Documents"];

    NSString *filePath = [documentsDirectory 
                          stringByAppendingPathComponent:@"errorLog.txt"];

    // Write to the file
    [errorString writeToFile:filePath atomically:YES 
            encoding:NSUTF8StringEncoding error:&error];
}

答案 1 :(得分:1)

您应该检查save:方法是否报告任何错误,例如:

NSError *error = nil;
if (![[self managedObjectContext] save:&error])
{
    NSLog(@"Error %@", action, [error localizedDescription]);    
    NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
    // if there is a detailed errors - we can dump all of them
    if(detailedErrors != nil && [detailedErrors count] > 0) {
        for(NSError* detailedError in detailedErrors) {
            NSLog(@"  DetailedError: %@", [detailedError localizedDescription]);
        }
    }
    else { // in other case lets dump all the info we have about the error
        NSLog(@"  %@", [error userInfo]);
    }
}

最常见的失败原因之一是验证错误,例如,它可能期望在用户未输入字段时显示字段,或者可能期望该值小于XX个字符,依此类推。

基本上这意味着如果为客户端提供带有调试信息的新版本需要很长时间,您可以要求他们向您发送他们用来输入的数据示例。

答案 2 :(得分:1)

我无法确定这是原因,但可能是当应用程序进入后台时,由于某种原因,有时会超出处理此时间(backgroundTimeRemaining)的最大允许时间。来自Apple文档:

  

此属性包含应用程序必须在后台运行的时间,才能被系统强制终止。当应用程序在前台运行时,此属性中的值仍然适当大。如果应用程序使用beginBackgroundTaskWithExpirationHandler:方法启动一个或多个长时间运行的任务,然后转换为后台,则调整此属性的值以反映应用程序剩余运行的时间。

如果你的应用程序被杀死是因为保存上下文需要太长时间,Core Data可能会决定恢复以前的状态,以至少获得一致的内容。如果您可以从报告此问题的某些用户获取日志结果,则可以尝试在尝试保存上下文后记录属性值,以进行检查。