rzucanie wyjątku w objective-c / cocoa
Jaki jest najlepszy sposób na rzucenie wyjątku w objective-C / cocoa?
13 answers
Używam [NSException raise:format:]
w następujący sposób:
[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-23 18:18:43
Słowo przestrogi. W Objective-C, w przeciwieństwie do wielu podobnych języków, powinieneś unikać używania wyjątków dla typowych sytuacji błędów, które mogą wystąpić podczas normalnego działania.
Dokumentacja Apple dla Obj-C 2.0 stwierdza, co następuje:"ważne: wyjątki są zasobochłonne w Objective-C. nie należy używać WYJĄTKÓW do ogólnej kontroli przepływu lub po prostu do oznaczania błędów (np. plik nie jest dostępny)"
Koncepcyjny Apple Dokumentacja obsługi wyjątków wyjaśnia to samo, ale więcej słów: "ważne: należy zarezerwować używanie WYJĄTKÓW do programowania lub nieoczekiwanych błędów runtime, takich jak dostęp do kolekcji poza granicami, próby mutacji niezmiennych obiektów, wysłanie nieprawidłowej wiadomości i utrata połączenia z serwerem okien. Zazwyczaj tego rodzaju błędy są usuwane z wyjątkiem sytuacji, gdy aplikacja jest tworzona,a nie w czasie wykonywania. [.....] Zamiast WYJĄTKÓW, błąd obiekty (NSError) i mechanizm dostarczania błędów Cocoa są zalecanym sposobem komunikowania oczekiwanych błędów w aplikacjach Cocoa."
Powodem tego jest po części przestrzeganie idiomów programistycznych w Objective - C (używanie wartości zwracanych w prostych przypadkach i parametrów by-reference (często Klasa NSError) w bardziej złożonych przypadkach), po części to, że rzucanie i łapanie wyjątków jest znacznie droższe i wreszcie (i co najważniejsze, wprawia w zakłopotanie), że wyjątki Objective-C są cienkim opakowaniem wokół funkcji setjmp () i longjmp() w C, zasadniczo psujących ostrożną obsługę pamięci, zobacz to Wyjaśnienie .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 10:18:02
@throw([NSException exceptionWith…])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-27 18:35:25
Nie mam reputacji, aby skomentować odpowiedź ejamesa, więc chyba muszę umieścić swoją tutaj. W przypadku osób wywodzących się z środowiska Java należy pamiętać, że Java rozróżnia wyjątki od RuntimeException. Wyjątek jest wyjątkiem zaznaczonym, a wyjątek RuntimeException nie jest zaznaczony. W szczególności Java sugeruje użycie WYJĄTKÓW sprawdzonych dla "normalnych warunków błędu" i WYJĄTKÓW niezaznaczonych dla " błędów uruchomieniowych spowodowanych błędem programisty."Wydaje się, że należy stosować wyjątki Objective-C w tych samych miejscach można użyć wyjątku niezaznaczonego, a wartości zwracane przez kod błędu lub wartości NSError są preferowane w miejscach, w których można użyć wyjątku zaznaczonego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-08 14:24:36
Myślę, że aby być konsekwentnym, lepiej jest użyć @ throw z własną klasą, która rozszerza NSException. Następnie używasz tych samych notacji dla try catch finally:
@try {
.....
}
@catch{
...
}
@finally{
...
}
Apple wyjaśnia tutaj, jak rzucać i obsługiwać wyjątki: Wyłapywanie WYJĄTKÓW Rzucanie WYJĄTKÓW
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-27 22:23:10
Od ObjC 2.0 wyjątki Objective-C nie są już opakowaniem dla setjmp() longjmp () C i są kompatybilne z wyjątkiem C++, @try jest "darmowy", ale rzucanie i łapanie wyjątków jest znacznie droższe.
W każdym razie, twierdzenia (używając rodziny makr NSAssert i nscassert) rzucają NSException, a to rozsądne, aby używać ich jako Stanów Ries.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-06 21:39:59
Użyj NSError do komunikowania błędów, a nie WYJĄTKÓW.
Szybkie punkty o NSError:
NSError pozwala kodom błędów w stylu C (liczbom całkowitym) wyraźnie zidentyfikować główną przyczynę i, miejmy nadzieję, umożliwić obsłudze błędów przezwyciężenie błędu. Możesz bardzo łatwo zawijać kody błędów z bibliotek C, takich jak SQLite, w instancjach NSError.
NSError ma również tę zaletę, że jest obiektem i oferuje sposób na bardziej szczegółowe opisanie błędu z członkiem słownika userInfo.
Ale co najlepsze, NSError nie może zostać wyrzucony, więc zachęca do bardziej proaktywnego podejścia do obsługi błędów, w przeciwieństwie do innych języków, które po prostu rzucają gorącym ziemniakiem dalej i dalej w górę stosu wywołań, w którym to momencie można tylko zgłosić użytkownikowi i nie obsługiwać go w żaden znaczący sposób(nie jeśli wierzysz w przestrzeganie największej Zasady OOP ukrywania informacji).
Odnośnik: odniesienie
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 08:38:48
Tak nauczyłem się tego z "The Big Nerd Ranch Guide (4th edition)":
@throw [NSException exceptionWithName:@"Something is not right exception"
reason:@"Can't perform this operation because of this or that"
userInfo:nil];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-12 07:33:34
Możesz użyć dwóch metod do wywołania wyjątku w bloku try catch
@throw[NSException exceptionWithName];
Lub druga metoda
NSException e;
[e raise];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-23 11:04:28
Uważam, że nigdy nie należy używać WYJĄTKÓW do kontrolowania normalnego przepływu programu. Ale wyjątki powinny być rzucane, gdy jakaś wartość nie pasuje do pożądanej wartości.
Na przykład, jeśli jakaś funkcja akceptuje wartość, a ta wartość Nigdy nie może być równa nil, to dobrze jest usunąć wyjątek zamiast próbować zrobić coś "mądrego"...
Ries
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 19:42:42
Możesz rzucać wyjątki tylko wtedy, gdy znajdziesz się w sytuacji, która wskazuje na błąd programowania i chcesz zatrzymać działanie aplikacji. Dlatego najlepszym sposobem na wyrzucenie wyjątków jest użycie makr NSAssert i NSParameterAssert i upewnienie się, że ns_block_assertions nie jest zdefiniowane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-30 09:01:35
Przykładowy kod dla przypadku: @ throw ([NSException exceptionWithName:...
- (void)parseError:(NSError *)error
completionBlock:(void (^)(NSString *error))completionBlock {
NSString *resultString = [NSString new];
@try {
NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];
if(!errorData.bytes) {
@throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
}
NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
options:NSJSONReadingAllowFragments
error:&error];
resultString = dictFromData[@"someKey"];
...
} @catch (NSException *exception) {
NSLog( @"Caught Exception Name: %@", exception.name);
NSLog( @"Caught Exception Reason: %@", exception.reason );
resultString = exception.reason;
} @finally {
completionBlock(resultString);
}
}
Użycie:
[self parseError:error completionBlock:^(NSString *error) {
NSLog(@"%@", error);
}];
Kolejny bardziej zaawansowany przypadek użycia:
- (void)parseError:(NSError *)error completionBlock:(void (^)(NSString *error))completionBlock {
NSString *resultString = [NSString new];
NSException* customNilException = [NSException exceptionWithName:@"NilException"
reason:@"object is nil"
userInfo:nil];
NSException* customNotNumberException = [NSException exceptionWithName:@"NotNumberException"
reason:@"object is not a NSNumber"
userInfo:nil];
@try {
NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];
if(!errorData.bytes) {
@throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
}
NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
options:NSJSONReadingAllowFragments
error:&error];
NSArray * array = dictFromData[@"someArrayKey"];
for (NSInteger i=0; i < array.count; i++) {
id resultString = array[i];
if (![resultString isKindOfClass:NSNumber.class]) {
[customNotNumberException raise]; // <====== HERE is just the same as: @throw customNotNumberException;
break;
} else if (!resultString){
@throw customNilException; // <======
break;
}
}
} @catch (SomeCustomException * sce) {
// most specific type
// handle exception ce
//...
} @catch (CustomException * ce) {
// most specific type
// handle exception ce
//...
} @catch (NSException *exception) {
// less specific type
// do whatever recovery is necessary at his level
//...
// rethrow the exception so it's handled at a higher level
@throw (SomeCustomException * customException);
} @finally {
// perform tasks necessary whether exception occurred or not
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 11:32:31
Nie ma powodu, aby nie używać WYJĄTKÓW normalnie w objective C nawet do oznaczania wyjątków od reguł biznesowych. Apple może powiedzieć użyj NSError kogo to obchodzi. Obj C istnieje od dawna i w jednym czasie cała dokumentacja C++ mówi to samo. Powodem, dla którego nie ma znaczenia, jak kosztowne jest rzucanie i łapanie wyjątku, jest żywotność wyjątku jest wyjątkowo krótka i...to wyjątek od normalnego przepływu. Nigdy w życiu nie słyszałem, żeby ktoś mówił, że ten wyjątek wziął długo trzeba było rzucać i łapać.
Są też ludzie, którzy uważają, że samo objective C jest zbyt drogie i zamiast tego kodują w C lub c++. Więc mówienie, że zawsze używaj NSError jest źle poinformowane i paranoiczne.
Ale na pytanie tego wątku nie udzielono jeszcze odpowiedzi jaki jest najlepszy sposób na wyrzucenie wyjątku. Sposoby zwracania NSError są oczywiste.
Tak jest: [NSException raise:... @throw [[NSException alloc] initWithName.... lub @ throw [[MyCustomException... ?
Używam tutaj Zasady checked/unchecked nieco inaczej niż powyżej.
Rzeczywista różnica pomiędzy zaznaczonymi/niezaznaczonymi (używając tu metafory Javy) jest ważna -- > czy można odzyskać wyjątek. A przez odzyskiwanie mam na myśli nie tylko nie crash.
Więc używam niestandardowych klas WYJĄTKÓW z @ throw do odzyskiwania wyjątków, ponieważ prawdopodobnie będę miał jakąś metodę aplikacji, która szuka pewnych typów awarii w wielu @ catch blocks. Na przykład, jeśli mój aplikacja to bankomat, ja bym miał blok @ catch na "Wycofanie żądania usunięcia balanceexception".
Używam NSException: raise dla WYJĄTKÓW runtime, ponieważ nie mam możliwości odzyskania z wyjątku, poza tym, żeby złapać go na wyższym poziomie i zalogować. I nie ma sensu tworzyć do tego niestandardowej klasy.
W każdym razie to właśnie robię, ale jeśli jest lepszy, podobnie wyrazisty sposób, to też chciałbym wiedzieć. W moim własnym kodzie, ponieważ przestałem kodować C a hella dawno temu I nigdy nie zwracaj NSError, nawet jeśli został mi przekazany przez API.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-28 23:07:44