[Objective C] 04 Exceptions

프로그래밍/iPhone Dev 2009. 10. 28. 11:28 Posted by galad
Exceptions

CupWarningException.h
#import <Foundation/NSException.h>

@interface CupWarningException: NSException
@end


CupWarningException.m
#import "CupWarningException.h"

@implementation CupWarningException
@end


CupOverflowException.h
#import <Foundation/NSException.h>

@interface CupOverflowException: NSException
@end


CupOverflowException.m
#import "CupOverflowException.h"

@implementation CupOverflowException
@end


Cup.h
#import <Foundation/NSObject.h>

@interface Cup: NSObject {
    int level;
}

-(int) level;
-(void) setLevel: (int) i;
-(void) fill;
-(void) empty;
-(void) print;
@end


Cup.m
#import "Cup.h"
#import "CupWarningException.h"
#import "CupOverflowException.h"
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>

@implementation Cup
-(id) init {
    self = [super init];
   
    if(self) {
        [self setLevel: 0];
    }
   
    return self;
}

-(int) level {
    return level;
}

-(void) setLevel: (int) i {
    level = i;
   
    if(level > 100) {
        // throw overflow
        NSException* e =
            [CupOverflowException
                exceptionWithName: @"CupOverflowException"
                reason: @"The level is above 100"
                userInfo: nil
            ];
       
        @throw e;
    }
    else if(level >= 50) {
        // throw warning
        NSException* e =
            [CupWarningException
                exceptionWithName: @"CupWarningException"
                reason: @"The level is above or at 50"
                userInfo: nil
            ];
           
        @throw e;
    }
    else if(level < 0) {
        // throw exception
        NSException* e =
            [NSException
                exceptionWithName: @"CupUnderflowException"
                reason: @"The level is below 0"
                userInfo: nil
            ];
       
        @throw e;
    }
}

-(void) fill {
    [self setLevel: level + 10];
}

-(void) empty {
    [self setLevel: level - 10];
}

-(void) print {
    printf("Cup level is: %i\n", level);
}
@end


main.m
#import "Cup.h"
#import "CupOverflowException.h"
#import "CupWarningException.h"
#import <Foundation/NSString.h>
#import <Foundation/NSException.h>
#import <Foundation/NSAutoreleasePool.h>
#import <stdio.h>

int main(int argc, const char* argv[]) {

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
   
    Cup* cup = [[Cup alloc] init];
    int i;
   
    // this will work
    for(i = 0; i < 4; i++) {
        [cup fill];
        [cup print];
    }
   
    // this will throw exceptions
    for(i = 0; i < 7; i++) {
        @try {
            [cup fill];
        }
        @catch(CupWarningException* e) {
            printf("%s: ", [[e name] cString]);
        }
        @catch(CupOverflowException* e) {
            printf("%s: ", [[e name] cString]);
        }
        @finally {
            [cup print];
        }
    }
   
    // throw a generic exception
    @try {
        [cup setLevel: -1];
    }
    @catch(NSException* e) {
        printf("%s: %s\n", [[e name] cString], [[e reason] cString]);
    }
   
    // free memory
    [cup release];
    [pool release];

    system("PAUSE");
    return 0;
}


컴파일 시 -fobjc-exceptions 옵션을 추가하라고 해서 붙였더니 @throw 에서 컴파일러가 죽는 바람에 결과 확인 못함.
minGW의 gcc 컴파일러 문제인 듯.

Compiler: Default compiler
Building Makefile: "D:\Workspaces\ObjectiveC\05_Exceptions\Makefile.win"
Executing  make...
make.exe -f "D:\Workspaces\ObjectiveC\05_Exceptions\Makefile.win" all
gcc.exe -c Cup.m -o Cup.o -I"C:/GNUstep/GNUstep/System/Library/Headers"    -lobjc -fobjc-exceptions -lgnustep-base -fconstant-string-class=NSConstantString -enable-auto-import
Cup.m: In function `-[Cup setLevel:]':
Cup.m:34: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://www.mingw.org/bugs.shtml> for instructions.

make.exe: *** [Cup.o] Error 1
Execution terminated

위는 컴파일 로그.

예제에 따르면 결과는 다음과 같다.
Cup level is: 10
Cup level is: 20
Cup level is: 30
Cup level is: 40
CupWarningException: Cup level is: 50
CupWarningException: Cup level is: 60
CupWarningException: Cup level is: 70
CupWarningException: Cup level is: 80
CupWarningException: Cup level is: 90
CupWarningException: Cup level is: 100
CupOverflowException: Cup level is: 110
CupUnderflowException: The level is below 0

- exception 생성 방식을 제외하면 던지고 잡는 것은 자바와 비슷. finally도 마찬가지.
- NSException을 반드시 상속해서 사용할 필요는 없다고. @catch ( id e ){..} 으로 해도 된다.
 근데 이 경우 예외끼리의 구분은 catch 안에서 클래스를 구분해야 할 듯.

Type Introspection
Type introspection이란 runtime시에 해당 인스턴스가 어떤 클래스의 인스턴스인지 등을 알아내는 것을 의미합니다. 좀더 일반적으로 말하자면 runtime시에 어떤 타입인지, 무엇을 할 수 있는지 등, 실행중에 변할 수 있는 부분을 알아낼 수 있는 메커니즘을 말합니다. NSObject에는 이런 용도로 isMemberOfClass와 같은 메소드가 정의되어 있습니다.
if( [anObject isMemberOfClass:someClass] )

라고 한다면 anObject라는 인스턴스가 someClass라는 클래스 타입인지 아닌지를 알 수 있습니다. 즉 return 값이 YES이면 someClass의 타입이란 것입니다.
좀더 포괄적인 것으로는 isKindOfClass가 있습니다.
if( [anObject isKindOfClass:someClass] )

이것은 anObject의 수퍼클래스중 someClass가 있는가를 알아낼 수있게 합니다. 즉 someClass의 한 종류인지를 알 수있게 해준다는 것입니다. isMemberOfClass 경우는 직접적인 parent class, 다른 말로는 superclass의 형인지 아닌지를 알려주는데 반해, 이것은 직접적인 superclass가 아니어도 된다는 것입니다.
이외에도 주어진 객체가 특정 메시지에 반응하는지 아닌지를 알아내는 것등 introspection의 예는 많습니다.

- @"CupOverflowException"와 같은 것들은 constant NSString object란다. cString은 String constant로 char* .
즉 예외 생성 시 @"XXX"로 넣은 constant String을 cString 메소드로 가져다가 출력. 주소참조해서 문자가져온 듯.

'프로그래밍 > iPhone Dev' 카테고리의 다른 글

[Objective C] 06 Inheritance  (1) 2009.10.30
[Objective C] 05 The Id Type  (1) 2009.10.29
[Objective C] 03 Class Level Access  (0) 2009.10.27
[Objective C] 02 Access Privledges  (0) 2009.10.27
[Objective C] 01 Creating Classes  (0) 2009.10.27