[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
관련 설명은 Objective‐C Language Reference 박종암 jongampark@gmail.com 을 참고했음.
문제 있으면 알려주시길...

Class Level Access

클래스 변수와 인스턴스 변수 관련

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

static int count;

@interface ClassA: NSObject
+(int) initCount;
+(void) initialize;
@end


ClassA.m
#import "ClassA.h"

@implementation ClassA
-(id) init {
    self = [super init];
    count++;
    return self;
}

+(int) initCount {
    return count;
}

+(void) initialize {
    count = 0;
}
@end


main.m
#import "ClassA.h"
#import <stdio.h>

int main(int argc, const char* argv[]) {
    ClassA* c1 = [[ClassA alloc] init];
    ClassA* c2 = [[ClassA alloc] init];
   
    // print count
    printf("ClassA count: %i\n", [ClassA initCount]);
   
    ClassA* c3 = [[ClassA alloc] init];

    // print count again
    printf("ClassA count: %i\n", [ClassA initCount]);
   
    [ClassA initialize];
    printf("ClassA count: %i\n", [ClassA initCount]);
   
    [c1 release];
    [c2 release];
    [c3 release];
   
    system("PAUSE");
    return 0;
}


결과
ClassA count: 2
ClassA count: 3
ClassA count: 0
계속하려면 아무 키나 누르십시오 . . .

init 메소드가 id 타입을 반환하는 것에 주의
static int count = 0; 클래스 변수 선언 방식. 좋은 위치는 아님. 자바의 static class variables 구현하는 것처럼 하는 것이 더 나음.
The + denotes a class level function.
+(void) initialize 메소드는 Objective-C가 프로그램 시작 시 콜함. 또한 모든 클래스에 대해서 콜함. 클래스 레벨 변수를 초기화하기에 좋은 위치.

id
Objective-C는 동적인 언어입니다. 이 말은 runtime시에 객체가 변할 수 있다는 것을 의미하며, 또한 해당 객체에 대한 method도 변할 수 있습니다.. 이것은 Apple에서 만들던 Dylan의 설명서를 보면 쉽게 이해할 수 있을것입니다. 아무튼 이렇게 동적이다보니, 기존의 static typing을 하던 방식으로 객체에 대한 포인터를 사용하면 불편한 면이 있을 수 있겠습니다. 그래서인지 Objective-C 에는 모든 객체를 두루 포인팅할 수 있는 타입을 새로 정의해 놓았는데 바로 id입니다. 다음의 예를 봅시다.

id mySong = [[Song alloc] init];

이렇게 하면 mySong은 Song이라는 타입의 객체를 가르키게 됩니다.
물론 static typing을 써서 다음과 같이 할 수도 있습니다.

Song mySong = …

이것은 흡사 C/C++의 void *와 비슷합니다.
만약 아무것도 안가르키고 있다면 nil 이라는 이미 정의된 keyword를 null 객체를 가르키기 위해서 사용할 수 있습니다.

id mySong = nil;

id 타입은 객체에 대해서 어떤 정보도 가지고 있지 않습니다. 단지 가르키고 있는게 객체라는 것만을 의미할 뿐입니다. 그러므로 id 로 선언된 변수는 어떤 객체라도 가르킬 수 있습니다. 이것은 C/C++ 관점에서 보자면 문제를 일으킬 수 있습니다. 즉 가르키고 있는 객체가 어떤 형태인줄 알아야 뭔가를 할 수 있을텐데, 이것만으로는 알아낼 방도가 없기 때문입니다. 그래서 isa 라는 instance variable을 묵시적으로 가지고 있게 됩니다. 이것은 실제 그 객체가 어떤 형인지를 기록해 놓는 것인데, 이것을 이용해서 runtime시에 알아낼 수 있게 됩니다.
이런 메커니즘을 이용해서 dynamic typing이 가능해 집니다.

즉, init 메소드에서 id 타입으로 반환하고 동적으로 typing해서 사용.

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

[Objective C] 05 The Id Type  (1) 2009.10.29
[Objective C] 04 Exceptions  (0) 2009.10.28
[Objective C] 02 Access Privledges  (0) 2009.10.27
[Objective C] 01 Creating Classes  (0) 2009.10.27
[Objective C] 환경설정  (0) 2009.10.27
Access Privledges

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

@interface Access: NSObject {
    @public
        int publicVar;
    @private
        int privateVar;
        int privateVar2;
    @protected
        int protectedVar;
}
@end


Access.m
#import "Access.h"

@implementation Access
@end


main.m
#import "Access.h"
#import <stdio.h>

int main(int argc, const char* argv[]) {
    Access* a = [[Access alloc] init];
   
    // Works
    a->publicVar = 5;
    printf("public var: %i\n", a->publicVar);
   
    // doesn't compile
//    a->privateVar = 10;
//    printf("private var: %i\n", a->privateVar);
   
    [a release];
   
    system("PAUSE");
    return 0;
}


인스턴스 내의 변수에 직접 접근 시에는 -> 사용

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

[Objective C] 04 Exceptions  (0) 2009.10.28
[Objective C] 03 Class Level Access  (0) 2009.10.27
[Objective C] 01 Creating Classes  (0) 2009.10.27
[Objective C] 환경설정  (0) 2009.10.27
[Objective C] 튜토리얼  (0) 2009.10.14
이후 관련 소스는 http://www.otierney.net/objective-c.html 를 참고했음.

Creating Classes

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

@interface Fraction: NSObject {
    int numerator;
    int denominator;
}

-(Fraction*) initWithNumerator: (int) n andDenominator: (int) d;
-(void) print;
-(void) setNumerator: (int) n;
-(void) setNumerator: (int) n andDenominator: (int) d;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end


Fraction.m
#import "Fraction.h"
#import <stdio.h>

@implementation Fraction
-(Fraction*) initWithNumerator: (int) n andDenominator: (int) d {
    self = [super init];
   
    if(self) {
        [self setNumerator: n andDenominator: d];
    }
   
    return self;
}

-(void) print {
    printf( "%i/%i", numerator, denominator );
}

-(void) setNumerator: (int) n {
    numerator = n;
}

-(void) setNumerator: (int) n andDenominator: (int) d {
    numerator = n;
    denominator = d;
}

-(void) setDenominator: (int) d {
    denominator = d;
}

-(int) denominator {
    return denominator;
}

-(int) numerator {
    return numerator;
}
@end


main.m
#import <stdio.h>
#import "Fraction.h"

int main( int argc, const char *argv[] ) {
    // create a new instance
    Fraction *frac = [[Fraction alloc] init];
    Fraction *frac2 = [[Fraction alloc] init];
    Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 andDenominator: 10];

    // set the values
    [frac setNumerator: 1];
    [frac setDenominator: 3];
   
    // combined set
    [frac2 setNumerator: 1 andDenominator: 5];

    // print it
    printf( "The fraction is: " );
    [frac print];
    printf( "\n" );
   
    // print it
    printf("Fraction 2 is: ");
    [frac2 print];
    printf( "\n" );
   
    // print it
    printf("Fraction 3 is: ");
    [frac3 print];
    printf( "\n" );

    // free memory
    [frac release];
    [frac2 release];
    [frac3 release];
   
    system("PAUSE");

    return 0;
}


[클래스 메소드명]의 메소드 호출 방식
객체 할당 후 초기화 잊지말기
메소드 호출 시에 인자 넘기는 경우, 인자에 이름 붙이기 가능

Objective-C 다운 표현으로는 [receiver message]. 리시버에게 메시지를 보낸다고 표현

메소드 정의 시의 +/-
- Instance method
+ Class method

[Objective C] 환경설정

프로그래밍/iPhone Dev 2009. 10. 27. 14:26 Posted by galad
공부할 환경을 설정.

출처: http://umaking.tistory.com/45

위 블로그 참고할 것

참고로 Dev-C는 영문버전으로 설정할 것. 한글로 할 경우 프로젝트에 .m 파일이 인식 안되는 버그 있음.

[Objective C] 튜토리얼

프로그래밍/iPhone Dev 2009. 10. 14. 15:11 Posted by galad
http://blog.lyxite.com/2008/01/compile-objective-c-programs-using-gcc.html
http://www.otierney.net/objective-c.html

http://umaking.tistory.com/45

compile

$ gcc Fraction.m main.m  -I /home/uclick/GNUstep/Local/Library/Headers -L /home/uclick/GNUstep/Local/Library/Libraries/
 -lobjc -lgnustep-base -enable-auto-import
출처: http://khie74.tistory.com/1169521335

일단 windows에서 유닉스 환경을 사용하기 위해 cygwin을 설치.

다음은 출처의 내용을 따른다.

설치할 때 다음의 패키지를 추가한다.

gcc-core:C compiler
gcc-g++:C++ compiler(C++도 함께 사용하는 경우에)
gcc-objc:ObjC compiler

테스트해보기

에디터로 다음의 hello.h와 hello.m을 작성한다.

// hello.h
#import <objc/Object.h>

@interface Hello : Object
-(void)print;
@end

// hello.m
#import <stdio.h>
#import "hello.h"

@implementation Hello
-(void)print
{
  printf("Hello world\n");
}
@end

int main()
{
  id obj = [Hello alloc];
  [obj print];
  return 0;
}

자~ 이제 컴파일을 해보자~

gcc -v -o hello hello.m -lobjc
(옵션 -v는 컴파일 과정 출력  -0는 출력파일명지정 -lobjc는 Objective-C라이브러리 사용)

컴파일이 성공한 후, 생성된 실행파일을 실행하면 아래와 같이 "Hello world"가 콘솔에 출력된다.


http://wisdom.sakura.ne.jp/programming/objc/index.html
http://cocoadev.tistory.com/10

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

[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
[Objective C] 환경설정  (0) 2009.10.27
[Objective C] 튜토리얼  (0) 2009.10.14