Pracuję nad wyłapywaniem błędów w mojej aplikacji i zamierzam używać NSError
. Jestem nieco zdezorientowany, jak go używać i jak go wypełnić.
Czy ktoś mógłby podać przykład, w jaki sposób wypełnić, a następnie użyć NSError
?
Cóż, zwykle robię to, aby moje metody, które mogą powodować błędy w czasie wykonywania, odwołują się do NSError
wskaźnika. Jeśli coś rzeczywiście pójdzie nie tak w tej metodzie, mogę wypełnić NSError
odwołanie danymi błędu i zwrócić zero z metody.
Przykład:
- (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;
}
Następnie możemy użyć takiej metody. Nie zawracaj sobie nawet głowy sprawdzaniem obiektu błędu, chyba że metoda zwróci zero:
// 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.
Udało nam się uzyskać dostęp do błędów, localizedDescription
ponieważ ustawiliśmy wartość dla NSLocalizedDescriptionKey
.
Najlepszym miejscem na więcej informacji jest dokumentacja Apple . To jest naprawdę dobre.
Jest też ładny, prosty samouczek na temat Cocoa Is My Girlfriend .
id
DoBOOL
. Wszelkie drobne zmiany kompatybilne z ARC byłyby bardzo mile widziane.BOOL
. ZwróćNO
w przypadku błędu i zamiast sprawdzać zwracaną wartość, po prostu sprawdźerror
. Jeślinil
śmiało, to!= nil
załatw to.**error
nie ma wartości zero. W przeciwnym razie program zgłosi błąd, który jest całkowicie nieprzyjazny i nie pokazuje, co się dzieje.Chciałbym dodać kilka sugestii w oparciu o moją najnowszą implementację. Przejrzałem kod firmy Apple i myślę, że mój kod zachowuje się w podobny sposób.
Powyższe posty już wyjaśniają, jak tworzyć obiekty NSError i zwracać je, więc nie będę zawracał sobie głowy tą częścią. Spróbuję zaproponować dobry sposób na integrację błędów (kodów, komunikatów) we własnej aplikacji.
Zalecam utworzenie 1 nagłówka, który będzie przeglądem wszystkich błędów Twojej domeny (tj. Aplikacji, biblioteki itp.). Mój obecny nagłówek wygląda następująco:
FSError.h
FSError.m
Teraz, używając powyższych wartości błędów, Apple utworzy podstawowy komunikat o błędzie dla Twojej aplikacji. Błąd może zostać utworzony w następujący sposób:
Standardowy komunikat błędu wygenerowany przez Apple (
error.localizedDescription
) dla powyższego kodu będzie wyglądał następująco:Error Domain=com.felis.myapp Code=1002 "The operation couldn’t be completed. (com.felis.myapp error 1002.)"
Powyższe jest już bardzo pomocne dla programisty, ponieważ komunikat wyświetla domenę, w której wystąpił błąd i odpowiedni kod błędu. Użytkownicy końcowi nie będą mieli pojęcia, co
1002
oznacza kod błędu , dlatego teraz musimy zaimplementować kilka miłych komunikatów dla każdego kodu.W przypadku komunikatów o błędach należy pamiętać o lokalizacji (nawet jeśli od razu nie wdrażamy zlokalizowanych komunikatów). W moim obecnym projekcie zastosowałem następujące podejście:
1) utwórz
strings
plik, który będzie zawierał błędy. Pliki ciągów można łatwo zlokalizować. Plik może wyglądać następująco:FSError.strings
2) Dodaj makra w celu konwersji kodów liczb całkowitych na zlokalizowane komunikaty o błędach. Użyłem 2 makr w moim pliku Constants + Macros.h.
MyApp-Prefix.pch
Dla wygody zawsze dołączam ten plik do nagłówka prefiksu ( ).Stałe + Makra. H
3) Teraz łatwo jest wyświetlić przyjazny dla użytkownika komunikat o błędzie oparty na kodzie błędu. Przykład:
źródło
Constants+Macros.h
i importuję ten plik do nagłówka (.pch
pliku) prefiksu, aby był dostępny wszędzie. Jeśli masz na myśli, że używasz tylko 1 z 2 makr, może to działać. Być może konwersja zint
naNSString
nie jest naprawdę konieczna, chociaż tego nie testowałem..strings
pliku), który można zlokalizować , ponieważ tam właśnie będzie wyglądać makro Apple. Przeczytaj o korzystaniuNSLocalizedStringFromTable
tutaj: developer.apple.com/library/mac/documentation/cocoa/conceptual/…FS_ERROR_LOCALIZED_DESCRIPTION
sprawdza ciąg lokalizowalny w pliku o nazwieFSError.strings
. Możesz sprawdzić przewodnik lokalizacyjny Apple dla.strings
plików, jeśli jest to dla Ciebie obce.Świetna odpowiedź Alex. Jednym potencjalnym problemem jest dereferencja NULL. Referencje Apple na temat tworzenia i zwracania obiektów NSError
źródło
Cel C
Szybki 3
źródło
Zapoznaj się z następującym samouczkiem
mam nadzieję, że będzie to dla ciebie pomocne, ale zanim będziesz musiał przeczytać dokumentację NSError
To bardzo interesujący link, który niedawno znalazłem ErrorHandling
źródło
Spróbuję streścić świetną odpowiedź Alexa i punkt jlmendezbonini, dodając modyfikację, która sprawi, że wszystko będzie kompatybilne z ARC (do tej pory nie jest tak, ponieważ ARC będzie narzekać, ponieważ powinieneś powrócić
id
, co oznacza „dowolny obiekt”, aleBOOL
nie jest przedmiotem rodzaj).Teraz zamiast sprawdzania wartości zwracanej przez nasze wywołanie metody, sprawdzamy, czy
error
nadal jestnil
. Jeśli nie, mamy problem.źródło
Inny wzorzec projektowy, który widziałem, obejmuje użycie bloków, co jest szczególnie przydatne, gdy metoda jest uruchamiana asynchronicznie.
Powiedzmy, że mamy zdefiniowane następujące kody błędów:
Zdefiniowałbyś metodę, która może wywoływać taki błąd:
A kiedy go wywołujesz, nie musisz się martwić o zadeklarowanie obiektu NSError (uzupełnienie kodu zrobi to za Ciebie) lub sprawdzenie zwracanej wartości. Możesz po prostu podać dwa bloki: jeden, który zostanie wywołany, gdy wystąpi wyjątek, i drugi, który zostanie wywołany, gdy się powiedzie:
źródło
Cóż, to trochę poza zakresem pytania, ale jeśli nie masz opcji NSError, zawsze możesz wyświetlić błąd niskiego poziomu:
źródło
którego mogę użyć,
NSError.defaultError()
gdy nie mam prawidłowego obiektu błędu.źródło