iPhone核心数据“生产”error handling

我在苹果提供的示例代码中看到了如何处理核心数据错误。 即:

NSError *error = nil; if (![context save:&error]) { /* Replace this implementation with code to handle the error appropriately. abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button. */ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } 

但从来没有任何例子,你应该如何实施它。

有没有人(或可以指向我的方向)一些实际的“生产”代码,说明上述方法。

在此先感谢,马特

没有人会告诉你生产代码,因为它取决于你的应用程序的100%和错误发生的地方。

就我个人而言,我在这里提出了一个断言,因为99.9%的时间会在开发过程中出现这个错误,当你在那里修复时,你不太可能在生产中看到它。

在断言之后,我会向用户显示一个警报,让他们知道发生了一个不可恢复的错误,并且应用程序将要退出。 你也可以在那里要求他们联系开发者,这样你就可以跟踪完成了。

之后,我会离开abort()在那里,因为它会“崩溃”的应用程序,并生成一个堆栈跟踪,你可以稍后使用,以追查问题。

这是我想出的在iPhone上处理和显示validation错误的一种通用方法。 但马库斯是正确的:你可能想调整消息更加用户友好。 但是,这至less给你一个起点,看看什么领域没有validation,为什么。

 - (void)displayValidationError:(NSError *)anError { if (anError && [[anError domain] isEqualToString:@"NSCocoaErrorDomain"]) { NSArray *errors = nil; // multiple errors? if ([anError code] == NSValidationMultipleErrorsError) { errors = [[anError userInfo] objectForKey:NSDetailedErrorsKey]; } else { errors = [NSArray arrayWithObject:anError]; } if (errors && [errors count] > 0) { NSString *messages = @"Reason(s):\n"; for (NSError * error in errors) { NSString *entityName = [[[[error userInfo] objectForKey:@"NSValidationErrorObject"] entity] name]; NSString *attributeName = [[error userInfo] objectForKey:@"NSValidationErrorKey"]; NSString *msg; switch ([error code]) { case NSManagedObjectValidationError: msg = @"Generic validation error."; break; case NSValidationMissingMandatoryPropertyError: msg = [NSString stringWithFormat:@"The attribute '%@' mustn't be empty.", attributeName]; break; case NSValidationRelationshipLacksMinimumCountError: msg = [NSString stringWithFormat:@"The relationship '%@' doesn't have enough entries.", attributeName]; break; case NSValidationRelationshipExceedsMaximumCountError: msg = [NSString stringWithFormat:@"The relationship '%@' has too many entries.", attributeName]; break; case NSValidationRelationshipDeniedDeleteError: msg = [NSString stringWithFormat:@"To delete, the relationship '%@' must be empty.", attributeName]; break; case NSValidationNumberTooLargeError: msg = [NSString stringWithFormat:@"The number of the attribute '%@' is too large.", attributeName]; break; case NSValidationNumberTooSmallError: msg = [NSString stringWithFormat:@"The number of the attribute '%@' is too small.", attributeName]; break; case NSValidationDateTooLateError: msg = [NSString stringWithFormat:@"The date of the attribute '%@' is too late.", attributeName]; break; case NSValidationDateTooSoonError: msg = [NSString stringWithFormat:@"The date of the attribute '%@' is too soon.", attributeName]; break; case NSValidationInvalidDateError: msg = [NSString stringWithFormat:@"The date of the attribute '%@' is invalid.", attributeName]; break; case NSValidationStringTooLongError: msg = [NSString stringWithFormat:@"The text of the attribute '%@' is too long.", attributeName]; break; case NSValidationStringTooShortError: msg = [NSString stringWithFormat:@"The text of the attribute '%@' is too short.", attributeName]; break; case NSValidationStringPatternMatchingError: msg = [NSString stringWithFormat:@"The text of the attribute '%@' doesn't match the required pattern.", attributeName]; break; default: msg = [NSString stringWithFormat:@"Unknown error (code %i).", [error code]]; break; } messages = [messages stringByAppendingFormat:@"%@%@%@\n", (entityName?:@""),(entityName?@": ":@""),msg]; } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Validation Error" message:messages delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alert show]; [alert release]; } } } 

请享用。

我发现这个常见的保存function更好的解决scheme:

 - (BOOL)saveContext { NSError *error; if (![self.managedObjectContext save:&error]) { DDLogError(@"[%@::%@] Whoops, couldn't save managed object context due to errors. Rolling back. Error: %@\n\n", NSStringFromClass([self class]), NSStringFromSelector(_cmd), error); [self.managedObjectContext rollback]; return NO; } return YES; } 

每当保存失败时,这将回滚您的NSManagedObjectContext,这意味着它将重置上次保存后在上下文中执行的所有更改 。 因此,您必须小心谨慎地使用上述保存function,尽可能提前并定期保持更改,否则可能会轻易丢失数据。

对于插入数据,这可能是一个更宽松的变体,允许其他更改生活在:

 - (BOOL)saveContext { NSError *error; if (![self.managedObjectContext save:&error]) { DDLogError(@"[%@::%@] Whoops, couldn't save. Removing erroneous object from context. Error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), object.objectId, error); [self.managedObjectContext deleteObject:object]; return NO; } return YES; } 

注意:我正在使用CocoaLumberjack进行login。

任何评论如何改善这是更受欢迎!

BR Chris

我很惊讶没有人在这里实际上处理错误的方式是要处理的。 如果你看文档,你会看到。

这里错误的典型原因包括:*设备空间不足。 *由于设备locking时的权限或数据保护,永久存储不可访问。 *商店无法迁移到当前的型号版本。 *父目录不存在,不能创build或不允许写入。

因此,如果在设置核心数据堆栈时发现错误,则交换UIWindow的rootViewController并显示UI,以清楚地告诉用户其设备可能已满,或者其安全设置太高,无法运行。 我也给他们一个“再试一次”的button,这样他们可以在重新尝试核心数据堆栈之前尝试修复这个问题。

例如,用户可以释放一些存储空间,返回到我的应用程序,然后按再次尝试button。

断言? 真? 房间里开发人员太多了!

我也惊讶于在线教程的数量,没有提到如何保存操作可能会因为这些原因而失败。 所以你将需要确保任何在你的应用程序任何保存事件可能会失败,因为设备只是这个分钟变得充满了你的应用程序节省存储节省。

我已经做了@JohannesFahrenkrug的有用答案的Swift版本可以是有用的:

 public func displayValidationError(anError:NSError?) -> String { if anError != nil && anError!.domain.compare("NSCocoaErrorDomain") == .OrderedSame { var messages:String = "Reason(s):\n" var errors = [AnyObject]() if (anError!.code == NSValidationMultipleErrorsError) { errors = anError!.userInfo[NSDetailedErrorsKey] as! [AnyObject] } else { errors = [AnyObject]() errors.append(anError!) } if (errors.count > 0) { for error in errors { if (error as? NSError)!.userInfo.keys.contains("conflictList") { messages = messages.stringByAppendingString("Generic merge conflict. see details : \(error)") } else { let entityName = "\(((error as? NSError)!.userInfo["NSValidationErrorObject"] as! NSManagedObject).entity.name)" let attributeName = "\((error as? NSError)!.userInfo["NSValidationErrorKey"])" var msg = "" switch (error.code) { case NSManagedObjectValidationError: msg = "Generic validation error."; break; case NSValidationMissingMandatoryPropertyError: msg = String(format:"The attribute '%@' mustn't be empty.", attributeName) break; case NSValidationRelationshipLacksMinimumCountError: msg = String(format:"The relationship '%@' doesn't have enough entries.", attributeName) break; case NSValidationRelationshipExceedsMaximumCountError: msg = String(format:"The relationship '%@' has too many entries.", attributeName) break; case NSValidationRelationshipDeniedDeleteError: msg = String(format:"To delete, the relationship '%@' must be empty.", attributeName) break; case NSValidationNumberTooLargeError: msg = String(format:"The number of the attribute '%@' is too large.", attributeName) break; case NSValidationNumberTooSmallError: msg = String(format:"The number of the attribute '%@' is too small.", attributeName) break; case NSValidationDateTooLateError: msg = String(format:"The date of the attribute '%@' is too late.", attributeName) break; case NSValidationDateTooSoonError: msg = String(format:"The date of the attribute '%@' is too soon.", attributeName) break; case NSValidationInvalidDateError: msg = String(format:"The date of the attribute '%@' is invalid.", attributeName) break; case NSValidationStringTooLongError: msg = String(format:"The text of the attribute '%@' is too long.", attributeName) break; case NSValidationStringTooShortError: msg = String(format:"The text of the attribute '%@' is too short.", attributeName) break; case NSValidationStringPatternMatchingError: msg = String(format:"The text of the attribute '%@' doesn't match the required pattern.", attributeName) break; default: msg = String(format:"Unknown error (code %i).", error.code) as String break; } messages = messages.stringByAppendingString("\(entityName).\(attributeName):\(msg)\n") } } } return messages } return "no error" }`