Как я могу использовать NSError в своем приложении для iPhone?
Я работаю над ловлей ошибок в моем приложении, и я ищу в использовании NSError. Я немного смущен о том, как его использовать, и как его заполнить.
может ли кто-нибудь привести пример того, как я заполняю, а затем использую NSError?
8 ответов:
Ну, то, что я обычно делаю, это мои методы, которые могут ошибаться во время выполнения, берут ссылку на
NSErrorуказатель. Если что-то действительно пойдет не так в этом методе, я могу заполнитьNSErrorссылка с данными об ошибке и возврат nil из метода.пример:
- (id) 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 *error = [NSError errorWithDomain:@"world" code:200 userInfo:details]; // we couldn't feed the world's children...return nil..sniffle...sniffle return nil; } // wohoo! We fed the world's children. The world is now in lots of debt. But who cares? return YES; }затем мы можем использовать такой метод. Даже не потрудитесь проверить объект ошибки, если метод не возвращает nil:
// initialize NSError object NSError* error = nil; // try to feed the world id yayOrNay = [self endWorldHunger:smallAmountsOfMonies error:&error]; if (!yayOrNay) { // inspect error NSLog(@"%@", [error localizedDescription]); } // otherwise the world has been fed. Wow, your code must rock.мы смогли получить доступ к ошибке
localizedDescriptionпотому что мы устанавливаем значениеNSLocalizedDescriptionKey.лучшее место для получения дополнительной информации документация Apple. Это действительно хорошо.
есть также хороший, простой учебник по Какао-Это Моя Девушка.
Я хотел бы добавить еще несколько предложений, основанных на моей последней реализации. Я посмотрел на некоторый код от Apple, и я думаю, что мой код ведет себя примерно так же.
сообщения выше уже объясняют, как создавать объекты NSError и возвращать их, поэтому я не буду беспокоиться об этой части. Я просто попытаюсь предложить хороший способ интеграции ошибок (коды, сообщения) в вашем собственном приложении.
Я рекомендую создать 1 заголовок, который будет представлять собой обзор всех ошибки вашего домена (например, приложение, библиотека и т. д..). Мой текущий заголовок выглядит так:
FSError.h
FOUNDATION_EXPORT NSString *const FSMyAppErrorDomain; enum { FSUserNotLoggedInError = 1000, FSUserLogoutFailedError, FSProfileParsingFailedError, FSProfileBadLoginError, FSFNIDParsingFailedError, };FSError.м
#import "FSError.h" NSString *const FSMyAppErrorDomain = @"com.felis.myapp";теперь при использовании вышеуказанных значений для ошибок Apple создаст некоторое базовое стандартное сообщение об ошибке для вашего приложения. Ошибка может быть создана следующим образом:
+ (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; }стандартное сообщение об ошибке, сгенерированное Apple (
error.localizedDescription) для приведенного выше кода будет выглядеть следующим образом следующее:
Error Domain=com.felis.myapp Code=1002 "The operation couldn’t be completed. (com.felis.myapp error 1002.)"выше уже довольно полезно для разработчика, так как сообщение отображает домен, где произошла ошибка и соответствующий код ошибки. Конечные пользователи не будут иметь ни малейшего понятия, что код ошибки
1002означает, что теперь нам нужно реализовать несколько хороших сообщений для каждого кода.для сообщений об ошибках мы должны иметь в виду локализацию (даже если мы не реализуем локализованные сообщения сразу). Я использовал следующее подход в моем текущем проекте:
1) создать
stringsфайл, который будет содержать ошибки. Файлы строк легко локализуются. Файл может выглядеть следующим образом:FSError.строки
"1000" = "User not logged in."; "1001" = "Logout failed."; "1002" = "Parser failed."; "1003" = "Incorrect username or password."; "1004" = "Failed to parse FNID."
2) Добавьте макросы для преобразования целочисленных кодов в локализованные сообщения об ошибках. Я использовал 2 макроса в моих константах + макросы.H-файл. Я всегда включаю этот файл в заголовок префикса (
MyApp-Prefix.pch) для удобство.Константы+Макросы.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) теперь легко показать удобное сообщение об ошибке на основе кода ошибки. Пример:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:FS_ERROR_LOCALIZED_DESCRIPTION(error.code) delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show];
отличный ответ Алекс. Одной из потенциальных проблем является разыменование NULL. Ссылка Apple на создание и возврат объектов NSError
... [details setValue:@"ran out of money" forKey:NSLocalizedDescriptionKey]; 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 nil; ...
С
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"])
см. ниже учебник
Я надеюсь, что это будет полезно для вас, но прежде вы должны прочитать документацию NSError
Это очень интересная ссылка, которую я нашел недавно ErrorHandling
я попытаюсь обобщить отличный ответ Алекса и точку jlmendezbonini, добавив модификацию, которая сделает все совместимым с ARC (пока это не так, поскольку ARC будет жаловаться, так как вы должны вернуться
id, что означает "любой объект", ноBOOLне является типом объекта).- (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; }теперь вместо проверки возвращаемого значения нашего метода, мы проверяем, есть ли
errorпо-прежнемуnil. Если это не так, у нас есть проблема.// 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.
другой шаблон проектирования, который я видел, включает в себя использование блоков, что особенно полезно, когда метод выполняется асинхронно.
скажем, у нас есть следующие коды ошибок определены:
typedef NS_ENUM(NSInteger, MyErrorCodes) { MyErrorCodesEmptyString = 500, MyErrorCodesInvalidURL, MyErrorCodesUnableToReachHost, };вы бы определили свой метод, который может вызвать ошибку следующим образом:
- (void)getContentsOfURL:(NSString *)path success:(void(^)(NSString *html))success failure:(void(^)(NSError *error))failure { if (path.length == 0) { if (failure) { failure([NSError errorWithDomain:@"com.example" code:MyErrorCodesEmptyString userInfo:nil]); } return; } NSString *htmlContents = @""; // Exercise for the reader: get the contents at that URL or raise another error. if (success) { success(htmlContents); } }и затем, когда вы его вызываете, вам не нужно беспокоиться об объявлении объекта NSError (завершение кода сделает это за вас) или проверке возвращаемого значения. Вы можете просто поставьте два блока: один, который будет вызван, когда есть исключение, и тот, который будет вызван, когда он преуспеет:
[self getContentsOfURL:@"http://google.com" success:^(NSString *html) { NSLog(@"Contents: %@", html); } failure:^(NSError *error) { NSLog(@"Failed to get contents: %@", error); if (error.code == MyErrorCodesEmptyString) { // make sure to check the domain too NSLog(@"You must provide a non-empty string"); } }];
Ну это немного из области вопроса, но в случае, если у вас нет опции для NSError вы всегда можете отобразить ошибку низкого уровня:
NSLog(@"Error = %@ ",[NSString stringWithUTF8String:strerror(errno)]);
Comments