¿Cómo puedo usar NSError en mi aplicación de iPhone?


3 Answers

Me gustaría agregar algunas sugerencias más basadas en mi implementación más reciente. Miré un código de Apple y creo que mi código se comporta de la misma manera.

Las publicaciones anteriores ya explican cómo crear objetos NSError y devolverlos, por lo que no me molestaré con esa parte. Trataré de sugerir una buena manera de integrar errores (códigos, mensajes) en tu propia aplicación.

Recomiendo crear 1 encabezado que será una descripción general de todos los errores de su dominio (es decir, aplicación, biblioteca, etc.). Mi encabezado actual se ve así:

FSError.h

FOUNDATION_EXPORT NSString *const FSMyAppErrorDomain;

enum {
    FSUserNotLoggedInError = 1000,
    FSUserLogoutFailedError,
    FSProfileParsingFailedError,
    FSProfileBadLoginError,
    FSFNIDParsingFailedError,
};

FSError.m

#import "FSError.h" 

NSString *const FSMyAppErrorDomain = @"com.felis.myapp";

Ahora, al usar los valores anteriores para los errores, Apple creará un mensaje de error estándar básico para su aplicación. Se podría crear un error como el siguiente:

+ (FSProfileInfo *)profileInfoWithData:(NSData *)data error:(NSError **)error
{
    FSProfileInfo *profileInfo = [[FSProfileInfo alloc] init];
    if (profileInfo)
    {
        /* ... lots of parsing code here ... */

        if (profileInfo.username == nil)
        {
            *error = [NSError errorWithDomain:FSMyAppErrorDomain code:FSProfileParsingFailedError userInfo:nil];            
            return nil;
        }
    }
    return profileInfo;
}

El mensaje de error estándar generado por Apple ( error.localizedDescription ) para el código anterior se verá como el siguiente:

Error Domain=com.felis.myapp Code=1002 "The operation couldn't be completed. (com.felis.myapp error 1002.)"

Lo anterior ya es bastante útil para un desarrollador, ya que el mensaje muestra el dominio donde ocurrió el error y el código de error correspondiente. Sin embargo, los usuarios finales no tendrán idea de qué significa el código de error 1002 , por lo que ahora debemos implementar algunos mensajes agradables para cada código.

Para los mensajes de error, debemos tener en cuenta la localización (incluso si no implementamos mensajes localizados de inmediato). He utilizado el siguiente enfoque en mi proyecto actual:

1) crea un archivo de strings que contendrá los errores. Los archivos de cadenas son fácilmente localizables. El archivo podría verse como el siguiente:

FSError.strings

"1000" = "User not logged in.";
"1001" = "Logout failed.";
"1002" = "Parser failed.";
"1003" = "Incorrect username or password.";
"1004" = "Failed to parse FNID."

2) Agregue macros para convertir códigos enteros a mensajes de error localizados. He usado 2 macros en mi archivo Constants + Macros.h. Siempre MyApp-Prefix.pch este archivo en el encabezado del prefijo ( MyApp-Prefix.pch ) para mayor comodidad.

Constantes + Macros.h

// error handling ...

#define FS_ERROR_KEY(code)                    [NSString stringWithFormat:@"%d", code]
#define FS_ERROR_LOCALIZED_DESCRIPTION(code)  NSLocalizedStringFromTable(FS_ERROR_KEY(code), @"FSError", nil)

3) Ahora es fácil mostrar un mensaje de error amigable basado en un código de error. Un ejemplo:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" 
            message:FS_ERROR_LOCALIZED_DESCRIPTION(error.code) 
            delegate:nil 
            cancelButtonTitle:@"OK" 
            otherButtonTitles:nil];
[alert show];
Question

Estoy trabajando para detectar errores en mi aplicación, y estoy buscando utilizar NSError . Estoy un poco confundido sobre cómo usarlo y cómo poblarlo.

¿Alguien podría dar un ejemplo sobre cómo poblar y luego usar NSError ?




C objetivo

NSError *err = [NSError errorWithDomain:@"some_domain"
                                   code:100
                               userInfo:@{
                                           NSLocalizedDescriptionKey:@"Something went wrong"
                               }];

Swift 3

let error = NSError(domain: "some_domain",
                      code: 100,
                  userInfo: [NSLocalizedDescriptionKey: "Something went wrong"])



Bueno, está un poco fuera de alcance, pero en caso de que no tenga una opción para NSError, siempre puede mostrar el error de nivel bajo:

 NSLog(@"Error = %@ ",[NSString stringWithUTF8String:strerror(errno)]);



Trataré de resumir la gran respuesta de Alex y el punto de jlmendezbonini, agregando una modificación que hará que todo ARC sea compatible (hasta ahora no lo es ya que ARC se quejará dado que deberías devolver el id , lo que significa "cualquier objeto", pero BOOL no un tipo de objeto).

- (BOOL) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
    // begin feeding the world's children...
    // it's all going well until....
    if (ohNoImOutOfMonies) {
        // sad, we can't solve world hunger, but we can let people know what went wrong!
        // init dictionary to be used to populate error object
        NSMutableDictionary* details = [NSMutableDictionary dictionary];
        [details setValue:@"ran out of money" forKey:NSLocalizedDescriptionKey];
        // populate the error object with the details
        if (error != NULL) {
             // populate the error object with the details
             *error = [NSError errorWithDomain:@"world" code:200 userInfo:details];
        }
        // we couldn't feed the world's children...return nil..sniffle...sniffle
        return NO;
    }
    // wohoo! We fed the world's children. The world is now in lots of debt. But who cares? 
    return YES;
}

Ahora, en lugar de verificar el valor de retorno de nuestra llamada a método, verificamos si el error sigue siendo nil . Si no es así, tenemos un problema.

// initialize NSError object
NSError* error = nil;
// try to feed the world
BOOL success = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!success) {
   // inspect error
   NSLog(@"%@", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.



Related