programing

목적에서 예외를 두는 것

padding 2023. 4. 13. 20:40
반응형

목적에서 예외를 두는 것

objective-c/cocoa에서 예외를 두는 가장 좋은 방법은 무엇일까요?

용 i i i i를 쓴다.[NSException raise:format:]음음음같 뭇매하다

[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];

경고 하나 하죠.Objective-C에서는 많은 유사한 언어와 달리 통상적인 동작에서 발생할 수 있는 일반적인 오류 상황에 대한 예외를 사용하지 않도록 해야 합니다.

Obj-C 2.0용 애플의 문서에는 다음과 같이 기술되어 있습니다. "중요:예외는 Objective-C에서 리소스를 많이 사용합니다.일반적인 흐름 제어에 예외를 사용하거나 단순히 오류(파일에 액세스할 수 없는 경우 등)를 나타내기 위해 예외를 사용해서는 안 됩니다.

Apple의 예외 처리 개념에 관한 문서에서도 같은 설명을 하고 있습니다만, 다음과 같은 문구가 추가되어 있습니다.「중요:Out-of-Bounds 컬렉션 액세스, 불변 객체 변환 시도, 잘못된 메시지 전송, 윈도 서버 연결 끊김 등의 프로그래밍 또는 예기치 않은 런타임 오류에 대한 예외 사용을 예약해야 합니다.일반적으로 이러한 종류의 오류는 실행 시보다는 응용 프로그램 생성 시 예외와 함께 처리합니다.[.....] 예외 대신 오류 개체(NSError)와 코코아 오류 전달 메커니즘이 코코아 응용 프로그램에서 예상되는 오류를 전달하는 데 권장되는 방법입니다.

그 이유는 부분적으로 Objective-C의 프로그래밍 숙어를 준수하기 위해서이다(단순한 경우에는 반환값, 복잡한 경우에는 기준별 파라미터(종종 NSError 클래스) 사용).부분적으로 예외 투척과 캐치핑은 훨씬 더 비싸고 마지막으로 Objective-C 예외는 C의 setjmp() 및 longjmp() 함수 주위에 얇은 래퍼이며, 기본적으로 주의 깊은 메모리 처리를 망친다는 것은 이 설명을 참조하십시오.

@throw([NSException exceptionWith…])

가 Xcode를 인식합니다.@throw예: 「」)return★★★★★★★★★★★★★를 사용해 주세요.@throw구문은 사용자가 얻을 수 있는 잘못된 "Control may may to reach of non-void function" 경고를 방지합니다.[NSException raise:…].

ㅇㅇㅇㅇ.@throwNSException은 NSException입니다.

★★★에 [NSException raise:format:]체크된 예외입니다.예외는 선택 해제되어 있습니다.특히 Java는 "정상 오류 조건"에 대해 체크된 예외를 사용하고 "프로그래머 오류로 인한 런타임 오류"에 대해 체크되지 않은 예외를 사용할 것을 권장합니다.Objective-C 예외는 체크되지 않은 예외를 사용하는 것과 동일한 장소에서 사용해야 하며, 체크된 예외를 사용하는 장소에서는 오류 코드 반환 값 또는 NSError 값이 선호됩니다.

일관되게 NSException을 확장하는 클래스에는 @throw를 사용하는 것이 좋다고 생각합니다.그런 다음 최종적으로 try catch에 동일한 표기를 사용합니다.

@try {
.....
}
@catch{
...
}
@finally{
...
}

Apple은 여기서 예외를 던지고 처리하는 방법을 설명합니다.

  1. 예외 포착
  2. 예외 설정

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의 가장 큰 숨겨진 정보의 원칙을 따르는 것을 믿는 경우는 제외).

레퍼런스 링크: 레퍼런스

'빅 너드 목장 가이드 (제4판)'에서 배운 내용입니다.

@throw [NSException exceptionWithName:@"Something is not right exception"
                               reason:@"Can't perform this operation because of this or that"
                             userInfo:nil];

Try catch 블록에서 예외를 발생시키는 두 가지 방법을 사용할 수 있습니다.

@throw[NSException exceptionWithName];

또는 두 번째 방법

NSException e;
[e raise];

정상적인 프로그램 흐름을 제어하기 위해 예외를 사용해서는 안 된다고 생각합니다.그러나 일부 값이 원하는 값과 일치하지 않을 때는 예외를 두어야 합니다.

예를 들어, 어떤 함수가 어떤 값을 받아들이고 그 값이 영이 될 수 없는 경우, 어떤 '스마트'한 작업을 시도하기보다는 예외를 추적하는 것이 좋습니다.

리즈

프로그래밍 오류를 나타내는 상황에서 응용 프로그램 실행을 중지하려는 경우에만 예외를 발생시켜야 합니다.따라서 예외를 슬로우하는 가장 좋은 방법은 NSAssert 매크로와 NSParameterAssert 매크로를 사용하여 NS_BLOCK_ASSERTIONS가 정의되어 있지 않은지 확인하는 것입니다.

케이스 코드 예: @throw(NSException 예외)WithName:

- (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 상승:...]@throw [[NSException allocation ]initWithName...또는 @throw [[ My Custom ]예외...?

여기서는 체크/체크 해제 규칙을 위와 약간 다르게 사용합니다.

(여기서 Java 메타포 사용) 체크/체크박스의 실제 차이는 예외에서 회복할 수 있는지 여부가 중요합니다.그리고 회복이란 단지 추락이 아닌 것을 의미합니다.

복구 가능한 예외에는 @throw와 함께 커스텀 예외 클래스를 사용합니다.여러 @catch 블록에서 특정 유형의 오류를 찾는 앱 메서드가 있을 수 있기 때문입니다.예를 들어 앱이 ATM 머신인 경우 "WithdrawalRequest"의 @catch 블록을 사용합니다.ExceedsBalanceException"을 클릭합니다.

NSException:raise는 런타임 예외에 대해 사용합니다. 예외에서 회복할 방법이 없기 때문에 더 높은 수준에서 예외를 포착하여 기록하는 것 외에는 방법이 없습니다.이 때문에 커스텀클래스를 만드는 것은 의미가 없습니다.

어쨌든 저는 그렇게 하고 있습니다만, 더 나은, 비슷한 표현 방법이 있다면 저도 알고 싶습니다.제 코드로는 C의 코딩은 이미 오래전에 중단했기 때문에 API에 의해 NSError가 통과되어도 반환되지 않습니다.

언급URL : https://stackoverflow.com/questions/324284/throwing-an-exception-in-objective-c-cocoa

반응형