답변:
[NSException raise:format:]
다음과 같이 사용 합니다.
[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];
여기서주의 할 점. Objective-C에서는 많은 다른 언어와 달리 일반적으로 정상적인 작동에서 발생할 수있는 일반적인 오류 상황에 예외를 사용하지 않도록 노력해야합니다.
Obj-C 2.0에 대한 Apple의 설명서 는 다음과 같이 설명합니다. "중요 : Objective-C에서 예외는 리소스를 많이 사용합니다. 일반적인 흐름 제어에 예외를 사용하거나 단순히 오류 (예 : 파일에 액세스 할 수없는 파일)를 나타내서는 안됩니다."
Apple의 개념적인 예외 처리 문서 는 동일하지만 더 많은 단어로 설명합니다. "중요 : 범위를 벗어난 콜렉션 액세스, 변경 불가능한 오브젝트의 변경, 유효하지 않은 메시지 전송과 같은 예상치 않은 런타임 오류에 대한 예외 사용을 예약해야합니다. 창 서버와의 연결이 끊어짐 일반적으로 런타임이 아닌 응용 프로그램을 만들 때 예외를 제외하고 이러한 종류의 오류를 처리합니다 [.....] 예외 대신 오류 개체 (NSError) 및 Cocoa 오류 전달 메커니즘은 Cocoa 응용 프로그램에서 예상되는 오류를 전달하는 데 권장되는 방법입니다. "
이것의 이유는 부분적으로 예외를 던지고 잡는 것이 훨씬 비싸고 Objective-C의 프로그래밍 관용구 (간단한 경우에는 리턴 값을 사용하고 더 복잡한 경우에는 참조 매개 변수 (종종 NSError 클래스)를 사용함)를 고수하기 위해서입니다. 마지막으로 Objective-C 예외는 C의 setjmp () 및 longjmp () 함수 주위의 얇은 래퍼이며 본질적으로 신중한 메모리 처리를 망칠 수 있습니다. 만듭니다. 이 설명을 .
@throw([NSException exceptionWith…])
Xcode는 @throw
명령문과 같은 명령문을 함수 종료점으로 인식 return
합니다. @throw
구문을 사용 하면 잘못된 " 제어가 무효화 기능 끝에 도달 할 수 있습니다 "경고가 표시 되지 않습니다[NSException raise:…]
.
또한 @throw
NSException 클래스가 아닌 객체를 던지는 데 사용할 수 있습니다.
에 관해서 [NSException raise:format:]
. Java 배경에서 온 사람들에게는 Java가 Exception과 RuntimeException을 구분한다는 것을 기억할 것입니다. 예외는 확인 된 예외이며 RuntimeException은 확인되지 않습니다. 특히, Java는 "정상 오류 조건"에 대해 확인 된 예외를 사용하고 "프로그래머 오류로 인한 런타임 오류"에 대해 확인되지 않은 예외를 사용할 것을 제안합니다. Objective-C 예외는 검사되지 않은 예외를 사용하는 것과 동일한 위치에서 사용해야하며, 검사 된 예외를 사용하는 경우 오류 코드 리턴 값 또는 NSError 값이 선호됩니다.
ObjC 2.0부터 Objective-C 예외는 더 이상 C의 setjmp () longjmp ()에 대한 래퍼가 아니며 C ++ 예외와 호환되므로 @try는 "무료"이지만 예외를 던지고 잡는 것이 훨씬 비쌉니다.
어쨌든 (NSAssert 및 NSCAssert 매크로 패밀리를 사용하는) 어설 션은 NSException을 발생시키고 그 상태를 Ries 상태로 사용합니다.
NSError를 사용하여 예외가 아닌 장애를 전달하십시오.
NSError에 대한 빠른 포인트 :
NSError를 사용하면 C 스타일 오류 코드 (정수)가 근본 원인을 명확하게 식별하고 오류 처리기가 오류를 극복 할 수 있습니다. NSError 인스턴스에서 SQLite와 같은 C 라이브러리의 오류 코드를 매우 쉽게 래핑 할 수 있습니다.
NSError는 또한 객체라는 이점을 가지고 있으며 userInfo 사전 멤버로 오류를보다 자세하게 설명 할 수있는 방법을 제공합니다.
그러나 무엇보다도, NSError는 던져 질 수 없으므로 단순히 뜨거운 감자를 더 던지고 콜 스택을 위로 올리는 다른 언어와 달리 오류 처리에 대한 사전 대처 방식을 권장합니다. 의미있는 방식으로 처리되지 않습니다 (OOP의 가장 큰 정보 숨기고 있다고 믿는 경우는 아닙니다).
참조 링크 : 참조
프로그래밍 오류를 나타내는 상황에 처해 있고 응용 프로그램 실행을 중지하려는 경우에만 예외를 발생시켜야합니다. 따라서 예외를 발생시키는 가장 좋은 방법은 NSAssert 및 NSParameterAssert 매크로를 사용하고 NS_BLOCK_ASSERTIONS가 정의되어 있지 않은지 확인하는 것입니다.
사례의 샘플 코드 : @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);
}
}
사용 :
[self parseError:error completionBlock:^(NSString *error) {
NSLog(@"%@", error);
}];
다른 고급 사용 사례 :
- (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
}
}
비즈니스 규칙 예외를 나타 내기 위해 객관적인 C에서 일반적으로 예외를 사용하지 않는 이유는 없습니다. 애플은 걱정하는 NSError를 사용할 수 있다고 말할 수있다. Obj C는 오래 전부터 사용되어 왔으며 한 번에 모든 C ++ 문서에서도 같은 말을했습니다. 예외를 던지고 잡는 데 드는 비용이 중요하지 않은 이유는 예외의 수명이 매우 짧고 정상적인 흐름에 대한 예외이기 때문입니다. 나는 내 인생에서 누군가가 말하는 것을들은 적이 없다.
또한 목표 C 자체가 너무 비싸고 대신 C 또는 C ++로 코딩한다고 생각하는 사람들이 있습니다. 따라서 항상 NSError를 사용한다는 것은 잘못된 정보와 편집증입니다.
그러나이 스레드의 문제는 아직 예외를 던지는 가장 좋은 방법은 무엇입니까? NSError를 반환하는 방법은 분명합니다.
[NSException raise : ... @throw [[NSException alloc] initWithName .... 또는 @throw [[MyCustomException ...?
여기에서 확인 / 확인되지 않은 규칙을 위와 약간 다르게 사용합니다.
(여기에서 Java 메타포 사용) 확인 / 선택 취소의 실제 차이점은 중요합니다-> 예외에서 복구 할 수 있는지 여부입니다. 그리고 복구로 나는 단지 충돌하지 않음을 의미합니다.
따라서 복구 가능한 예외에 @throw와 함께 사용자 정의 예외 클래스를 사용합니다. 여러 @catch 블록에서 특정 유형의 실패를 찾는 일부 앱 메소드가 있기 때문입니다. 예를 들어 내 앱이 ATM 시스템 인 경우 "WithdrawalRequestExceedsBalanceException"에 대한 @catch 블록이 있습니다.
NSException : raise를 사용하면 예외를 더 높은 수준에서 잡아서 기록하는 것 외에는 예외에서 복구 할 수 없으므로 런타임 예외에 사용됩니다. 그리고이를위한 커스텀 클래스를 만들 필요는 없습니다.
어쨌든 그게 내가하는 일이지만, 더 좋고 비슷한 표현 방법이 있다면 나도 알고 싶습니다. 내 자신의 코드에서는 오래 전에 C 코딩을 중단했기 때문에 API에 의해 전달 된 경우에도 NSError를 반환하지 않습니다.
@throw([NSException exceptionWith…])
더 간결한 접근 방식에 따라이 방법을 선호합니다 .