usar tutorial porque existing espaƱol efecto data apple iphone core-data error-handling

iphone - tutorial - nsmanagedobject swift 4



Manejo de errores de "Core" de Core Data Data (5)

Encontré esta función de guardar común una solución mucho mejor:

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

Cada vez que falla un guardado, esto revertirá su NSManagedObjectContext, lo que significa que restablecerá todos los cambios que se han realizado en el contexto desde la última vez que se guardó . Por lo tanto, debe tener cuidado para no perder los cambios utilizando la función de guardado anterior tan pronto y con la mayor frecuencia posible, ya que de lo contrario podría perder fácilmente los datos.

Para insertar datos, esta podría ser una variante más flexible que permita que otros cambios permanezcan vigentes:

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

Nota: Estoy usando CocoaLumberjack para iniciar sesión aquí.

¡Cualquier comentario sobre cómo mejorar esto es más que bienvenido!

BR Chris

He visto en el código de ejemplo proporcionado por Apple referencias a cómo debe manejar los errores de Datos centrales. Es decir:

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(); }

Pero nunca hay ejemplos de cómo debe implementarlo.

¿Alguien tiene (o puede señalarme en la dirección de) algún código de "producción" real que ilustre el método anterior?

Gracias de antemano, Matt


Este es un método genérico que ideé para manejar y mostrar los errores de validación en el iPhone. Pero Marcus tiene razón: probablemente quieras ajustar los mensajes para que sean más fáciles de usar. Pero al menos esto le da un punto de partida para ver qué campo no validar y por qué.

- (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]; } } }

Disfrutar.


He hecho una versión Swift de la útil respuesta de @JohannesFahrenkrug que puede ser útil:

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" }`


Me sorprende que nadie aquí esté manejando el error de la manera en que debe ser manejado. Si miras la documentación, verás.

Las razones típicas de un error aquí incluyen: * El dispositivo está sin espacio. * La tienda persistente no es accesible, debido a permisos o protección de datos cuando el dispositivo está bloqueado. * La tienda no se pudo migrar a la versión del modelo actual. * El directorio principal no existe, no se puede crear o no permite la escritura.

Entonces, si encuentro un error al configurar la pila de datos centrales, cambio el control raíz de la ventana UI y le mostraré la IU que claramente le dice al usuario que su dispositivo puede estar lleno o que su configuración de seguridad es demasiado alta para que funcione esta aplicación. También les doy un botón "intentar de nuevo", para que puedan intentar solucionar el problema antes de que la pila de datos centrales se vuelva a intentar.

Por ejemplo, el usuario podría liberar algo de espacio de almacenamiento, volver a mi aplicación y presionar el botón "intentar de nuevo".

¿Afirma? De Verdad? Demasiados desarrolladores en la sala

También me sorprende el número de tutoriales en línea que no mencionan cómo una operación de salvar podría fallar por estos motivos también. Por lo tanto, deberá asegurarse de que cualquier evento guardado en CUALQUIER LUGAR de su Aplicación podría fallar debido a que el dispositivo SOLO ESTE MINUTO se llenó con sus Aplicaciones, lo que ahorró ahorros.


Nadie va a mostrarle el código de producción porque depende 100% de su aplicación y dónde ocurre el error.

Personalmente, puse una declaración de afirmación allí porque el 99.9% del tiempo este error va a ocurrir en el desarrollo y cuando lo arregles allí es muy poco probable que lo veas en producción.

Después de la afirmación, le presentaría una alerta al usuario, infórmele que ocurrió un error irrecuperable y que la aplicación va a salir. También puede poner una publicidad allí pidiéndoles que se pongan en contacto con el desarrollador para que pueda seguir esto.

Después de eso, dejaría el aborto () allí ya que "bloqueará" la aplicación y generará un seguimiento de la pila que esperemos usar más adelante para rastrear el problema.