2013-05-27 17 views
6

基于核心数据的iOS应用程序的一些客户偶尔会丢失数据。这些报道非常奇怪,这就是我想要请你承担这个问题的原因。客户报告说,当他们在一段时间(几分钟,几小时或次日)后重新打开应用程序时,他们的一些数据丢失,就好像底层数据库恢复到之前的状态一样。核心数据没有明显原因地恢复到以前的状态

我一直与核心数据工作了好几年,从来没有遇到过这样的问题。该应用程序非常简单,这意味着我只使用一个托管对象上下文,并且在应用程序转到后台之前提交更改。

我意识到这是一个远射,但什么可能是这种类型的问题的一些潜在原因或我可以做什么检查以收集更多信息?不幸的是,我不能自己重现这个问题,这会让这一切变得更容易。

更新:

- (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; 
} 
+0

你设置任何['pragma'选项](http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/CoreData/Articles/cdPersistentStores.html#//apple_ref/ doc/uid/TP40002875-SW12)在您的商店? –

+0

@DanShelly号我已经用你指的代码片段更新了这个问题。 –

+1

当**完全**您是否保存更改? –

回答

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

您应该检查是否​​方法报告的任何错误,例如像这样:

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字符等等。

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

1

我不能确定这是什么原因,但可能是因为某些原因,当应用程序转到后台时,有时会超出处理此最大允许时间(backgroundTimeRemaining)的时间。从Apple文档:

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

如果您的应用因为保存上下文耗时过长而死亡,Core Data可能会决定恢复之前的状态以至少获得一致的结果。如果您可以从报告此问题的某些用户那里获得日志结果,则可以在尝试保存上下文后尝试记录属性值,以检查此问题。

+0

正如我在问题中提到的那样,每当创建新实体时都会保存托管对象上下文,所以我相当肯定这不是问题的原因。感谢您的回答。 –