6

一些基于 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;
}
4

3 回答 3

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];
}
于 2013-06-03T14:58:37.400 回答
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 个字符等等。

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

于 2013-06-02T13:57:30.740 回答
1

我不能确定这是原因,但可能是当应用程序进入后台时,由于某种原因,有时超过了处理此问题的最大允许时间(backgroundTimeRemaining)。来自苹果文档:

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

如果你的应用程序因为保存上下文时间太长而被终止,Core Data 可能会决定恢复以前的状态以至少获得一致的东西。如果您可以从一些报告此问题的用户那里获得日志结果,您可以在尝试保存上下文后尝试记录属性值,以检查这一点。

于 2013-06-03T13:48:37.220 回答