我已经制作了一个Swift版本的@JohannesFahrenkrug有用的答案,它可能很有用:
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" }`
我很惊讶这里没有人真正按照它的处理方式处理错误。如果你查看文档,你会看到。
此处出现错误的典型原因包括:*设备已关闭 空间。 *持久性商店无法访问,原因是 设备锁定时的权限或数据保护。 * store无法迁移到当前模型版本。 * 父目录不存在,无法创建或不允许 写作。
因此,如果我在设置核心数据堆栈时发现错误,我会交换UIWindow的rootViewController并显示UI,清楚地告诉用户他们的设备可能已满,或者他们的安全设置太高而无法运行此应用程序。我还给他们一个'再试一次'按钮,这样他们就可以在重新尝试核心数据堆栈之前尝试解决问题。
例如,用户可以释放一些存储空间,返回我的应用程序并再次按下尝试按钮。
断言?真?房间里的开发人员太多了!
我也对在线教程的数量感到惊讶,因为这些原因也未提及保存操作如何失败。因此,您需要确保应用程序中的任何保存事件都可能失败,因为设备JUST THIS MINUTE已满,节省了您的Apps节省。
没有人会向您展示生产代码,因为它取决于您的应用程序以及发生错误的位置。
就个人而言,我在那里放了一个断言声明,因为99.9%的时间会在开发过程中出现这个错误,当你修复它时,它就是 高度 不太可能你会在生产中看到它。
在断言之后,我会向用户发出警报,让他们知道发生了不可恢复的错误,并且应用程序将要退出。您还可以在其中放置一个模糊信息,要求他们联系开发人员,以便您可以跟踪完成此操作。
之后我会将abort()留在那里,因为它会“崩溃”应用程序并生成一个堆栈跟踪,您可以在以后使用它来跟踪问题。
这是我提出的处理和显示iPhone验证错误的一种通用方法。但马库斯是对的:你可能想要调整消息以使用户更友好。但这至少为您提供了一个起点,看看哪个领域没有验证,为什么。
- (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]; } } }
请享用。
我发现这个常见的保存功能是一个更好的解决方案
- (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,这意味着它将重置自上次保存以来在上下文中执行的所有更改 强> 。因此,您必须尽可能早地和定期地使用上述保存功能仔细注意始终保持更改,否则您可能很容易丢失数据。
对于插入数据,这可能是一个更宽松的变体,允许其他更改生效:
- (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进行日志记录。
任何有关如何改进这一点的评论都是值得欢迎的!
BR 克里斯