*상속


상위 클래스의 멤버를 하위 클래스에게 물려주는 것을 상속이라고 합니다.

상위 클래스의 모든 멤버를 물려받습니다.

상위 클래스를 super class 또는 base class라고 하며 하위 클래스를 sub class 또는 derived class 라고도 합니다.

상속 방법

@interface 클래스이름: 상속하는 클래스

Objective C에서는 NSObject 클래스가 최상위 클래스이며 모든 클래스는 이 클래스로부터 상속을 받아야만 합니다.

Cocoa에서는 NSProxy라는 클래스도 최상위 클래스로 취급합니다.

다른 클래스가 이미 상속을 받았다면 그 클래스로부터 상속을 받아도 됩니다.


NSObject클래스에는  여러 가지 멤버가 정의되어 있습니다.

isa라는 멤버 변수와 메모리 할당과 관련된 alloc, dealloc, release, retain, finalize 같은 멤버 들을 가지고 있으며 init, initialize, new 등과 같은 초기화 메서드 들도 가지고 있습니다.

하위 클래스에서는 상위 클래스의 멤버를 다시 정의하지 않아도 있는 것으로 간주하며 자신의 멤버를 정의하고자 한다면 정의하고자 하는 내용을 기재하면 되고 정의할 내용이 없다면 블록만 연 후 닫아도 됩니다.

상속 시 상위 클래스와 하위 클래스에 동일한 멤버 변수의 정의는 안됩니다.

상위 클래스의 메서드를 하위 클래스에서 다시 정의해서 사용하는 것은 가능한데 이를 메서드 오버라이딩이라고 합니다.


예제

Test.h파일

#import <Foundation/Foundation.h>

@interface Test: NSObject

   int val; 

 }

- (id)init:(int)a;

@property int val; 

@end


Test.m파일

#import "Test.h"

@implementation Test

- (id)init:(int)a;

{

self = [super init];

if(self != nil)

val = a;

return self;      

}

@synthesize val;

@end


Main 메서드가 있는 파일

#import "Test.h"

@interface SubTest: Test

{}

@end

@implementation SubTest:Test

{}

@end

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

{

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

id obj1, obj2;    

    obj1 = [[Test alloc] init:10];

    NSLog(@"Obj1의 val: %d",[obj1 val]); 

    obj2 = [[SubTest alloc] init:20];

    NSLog(@"Obj2의 val: %d",[obj2 val]); 

    [pool drain];

    return 0;

}


앞의 프로젝트 수정(Main 파일)

#import "Test.h"

@interface SubTest: Test

- (id)increment;

@end


@implementation SubTest

-(id)increment

{

val += 1;

return self;

}                 

@end


int main(void)

{

    Test *obj1;

    SubTest *obj2;    

    obj1 = [[Test alloc] init:10];

    NSLog(@"Obj1의 val: %d\n",[obj1 val]); 

    obj2 = [[SubTest alloc] init:20];

obj2 = [obj2 increment];

    NSLog(@"Obj2의 val: %d\n",[obj2 val]); 

    return 0;

}


self

-self는 클래스 정의 내에서 객체가 자기 자신을 리턴 시키거나 자신의 멤버를 명시적으로 호출하는 경우 사용합니다.

-self는 클래스 정의 내에서만 사용해야 합니다.

-다른 곳에서 self를 호출하는 것은 안됩니다.

-지역 변수와 멤버 변수의 구분을 위해서 사용하며 Iphone SDK에서는 delegate 지정에 많이 사용합니다.

 -delegate는 수행해야 하는 메서드 들을 위임 받아서 대신 처리하는 객체입니다.

-특정 클래스들은 자신의 멤버 메서드 처리를 대신할 객체를 지정하도록 강제하는 경우가 있습니다. 

-self.프로퍼티 와 self->멤버변수 및 멤버변수 를 혼동하면 안됩니다.



예제(Main 파일 수정)

#import "Test.h"

@interface SubTest: Test

-(void)Disp;

@end


@implementation SubTest

-(void)Disp

{

NSLog(@"%d\n", [self val]+1);       

}                 

@end

int main(void)

{

    id obj;

    obj = [[SubTest alloc] init:20];

    [obj Disp]; 

    return 0;

}


super

상위 클래스의 멤버와 동일한 멤버를 하위 클래스에서 선언하거나 다시 정의하면 상위 클래스의 멤버는 가려 지므로 자신이 정의한 메서드는 self를 이용해서 호출하고 상위 클래스의 멤버는 super를 이용해서 호출해야 합니다.

상위 클래스에 있는 메서드를 하위 클래스에서 재정의 하는 것을 method overriding( 재정의) 이라고 합니다.

Iphone SDK에서 프로그래밍을 하는 경우 이러한 오버라이딩을 많이 이용합니다.

Iphone SDK에서 오버라이딩을 하는 경우에는 주의해야 합니다.

상위 클래스에 정의되어 있는 주요한 기능은 항상 상위 클래스의 메서드를 호출해서 그 작업을 하고 난 후 자신의 작업을 수행해야 합니다.


예제 – Main 파일 수정

#import "Test.h"

@interface SubTest: Test

-(int)val;

-(void)setVal:(int)temp;

@end

@implementation SubTest

-(int) val

{ return val;}

-(void)setVal:(int)temp

{

val = temp + 1;

}

@end

int main(void)

{

    id obj1, obj2;

    obj1 = [Test new];

[obj1 setVal:10];

NSLog(@"obj1의 val:%d", [obj1 val]);

obj2 = [SubTest new];

[obj2 setVal:10];

NSLog(@"obj2의 val:%d", [obj2 val]);

    return 0;

}

다형성과 동적 바인딩

-일반적으로 오버라이딩을 하는 이유는 다형성을 구현하기 위해서 입니다.

-다형성은 동일한 메시지에 대하여 서로 다르게 반응하는 성질입니다.

-다형성이 구현되기 위해서는 프로그래밍 언어가 동적 바인딩을 지원해야 합니다.

-동적바인딩이란 객체가 컴파일 시에 자신의 타입을 결정하지 않고 실행(메모리 할당)시에 자신의 타입을 결정하는 것입니다.

-선언이 될 때 사용된 타입은 무시하고 메모리를 할당받을 때 어떤 타입으로 할당받았는냐에 따라 동작하는 것입니다.

-Objective-C는 무조건 동적 바인딩입니다.

#import <Foundation/Foundation.h>

@interface Starcraft: NSObject

- (void)attack;

@end


@implementation Starcraft

- (void)attack { NSLog(@"Starcrft의 공격\n"); }

@end

@interface Zerg: Starcraft

- (void)attack;

@end


@implementation Zerg

- (void)attack { NSLog(@"Zerg의 공격\n"); }

@end

@interface Terran: Starcraft

- (void)attack;

@end

@implementation Terran

- (void)attack { NSLog(@"Terran의 공격\n"); }

@end

@interface Protoss: Starcraft

- (void)attack;

@end

@implementation Protoss

- (void)attack { NSLog(@"Protoss의 공격\n"); }

@end


int main(void)

{ int menu;

    Starcraft * obj;

while(YES)

    { 

NSLog(@"종족을 선택하세요:(1.저그 2.테란 3.프로토스)"); 

scanf("%d", &menu);

if(menu == 1)

{

obj = [[Zerg alloc] init];

[obj attack];

break;

}

else if(menu == 2){

obj = [[Terran alloc] init];

[obj attack];

break;

}

else if(menu == 3){

obj = [[Protoss alloc] init];

[obj attack];

break;

}

else{

NSLog(@"종족을 잘 선택하세요");

}

    }       

    return 0;   

}


클래스 객체

-클래스도 선언과 구현이 되면 하나의 객체처럼 취급할 수 있습니다.

-클래스도 독자적인 변수와 메서드를 가지고 있습니다.

-이를 일반적으로 클래스 변수 또는 클래스 메서드라고 부릅니다.

-클래스 객체는 Class라는 데이터 타입으로 정의되어 있습니다.

-NSObject 클래스에는 class 라는 메서드가 정의되어 있어서 클래스 객체를 리턴해줍니다.

1) 클래스 메서드

메서드를 선언할 때 –는 인스턴스 메서드를 의미하며 +는 클래스 메서드를 의미합니다.

즉 클래스 메서드와 인스턴스 메서드를 구분하기 위하여 사용하는 것입니다.

클래스 메서드는 클래스 객체만이 호출할 수 있으며 클래스 이름이 클래스 객체를 의미합니다.


2) 클래스 변수

Objective-C에서는 클래스 변수가 존재하지 않습니다.

클래스의 구현부에서 static이라는 키워드를 이용해서 구현파일 내에서만 접근이 가능한 변수를 생성할 수 있을 뿐입니다.

이 때 주의해야 합니다.

선언된 구현 파일 내에서만 접근이 가능하므로 상속받은 하위 클래스에서는 이를 접근할 수 없습니다.

동일한 파일r에 작성이 되어 있다면 접근이 가능합니다.

서로 다른 파일에 구현되어 있는 경우에는 클래스 메서드로 static 변수에 접근하도록 정의하고 이를 호출하는 방법으로 사용해야 합니다.

기본적으로 상속되지 않습니다.


예제

#import <Foundation/Foundation.h>

@interface Test: NSObject

{    

int val;

}

@property int val;

- (id)init:(int)a;

+ (void)Disp;

@end

@implementation Test

- (id)init:(int)a;

{

val = a;

return self;      

}

@synthesize val;

+(void)Disp

{

    NSLog(@"클래스의 메서드입니다"); 

}


int main(void)

{

NSAutoreleasePool *pool = [NSAutoreleasePool new];

    Test *obj1;  

    obj1 = [[Test alloc] init:10];

    NSLog(@"Obj1의 val: %d",obj1.val); 

// [obj1 Disp]; 

[Test Disp]; 

[pool drain];

return 0;

}

-------------------------------

예제

#import <Foundation/Foundation.h>

@interface Test: NSObject

{    

int number;    

}

-(id)init;

-(void)Disp;

@end

@implementation Test

static int sequence= 0;

- (id)init

{

self = [super init];

if(self)

number = ++sequence;

return self;

- (void)Disp

{

    NSLog(@"sequence: %d number: %d\n", sequence, number); 

}

@end

int main(void)

{

    Test *obj1, *obj2;  

    obj1 = [[Test alloc]init];

[obj1 Disp];

    obj2 = [[Test alloc]init];    

    [obj2 Disp];

return 0;

}

-------------------------------

nil 포인터

-다른 언어의 null과 유사하며 0의 값을 갖는 포인터 입니다.

-이 포인터는 어떠한 메시지 처리도 할 수 없습니다.

-그렇지만 이 포인터가 메시지 호출을 하는 경우 에러는 아닙니다.

-이 포인터는 메시지 호출을 하려고 하다가 실패하면 예외가 발생해서 프로그램이 종료될 것입니다.

-Iphone SDK 사용 시 주의해야 합니다.

-메서드가 구현되어 있지 않거나 메서드를 호출하는 리시버가 nil이라면 에러가 아니고 튕겨 나갑니다.

-일반적으로 init 메서드가 정상적으로 수행이 되지 않은 경우에도 nil을 리턴합니다.


지역 메서드

-선언부에는 없고 구현부에만 존재해서 구현 부분에서만 일시적으로 사용하는 메서드

-이 메서드를 외부에서 호출하면 경고가 발생할 것입니다.

-Iphone 프로그래밍에서는 이 메서드는 외부 객체의 이벤트(IBAction)가 될 수 없습니다.

-상속받은 경우와 혼동하면 안됩니다.


예제

#import <Foundation/Foundation.h>

@interface Temp: NSObject

{

    int val;

}

-(void)Disp;

-(id)init:(int) a;

@end

@implementation Temp

-(id)init:(int) a

{

val = a; 

return self;

}

-(int)value 

return val; 

}

-(void)Disp

{

NSLog(@"%i\n", [self value]);

}

@end

int main(void)

{

    id obj;

    obj=[[Temp alloc] init:10];

    [obj Disp];

    NSLog(@"%d\n",[obj value]);

    return 0;   

}


자료출처 : 맥부기 카페 (오브젝트c 상속에 관한것)

http://cafe.naver.com/mcbugi/111757

오브젝티브씨 시작하기...



오브젝티브씨! 이 초보적이고 재미없는 주제로 몇 자 적어보자 하는 것은... 처음 시작하는 분들이 조금이라도 방향을

잡았으면 하는 마음에서입니다. 또 개인적으로는 오브젝티브씨라는 언어가 주는 단순함이 좋고, 그네들의 프레임웍

설계 방식을 좋아하기 때문이기도 합니다. 애플이 주는 답답함에 애증이 교차하기도 합니다만...


어떤 것이든 시작은 어렵습니다. 그러나, 대충 아~ 이렇구나라고 느끼는 순간을 넘으면, 그 이후엔 거침없이 나아갈 수

있다고 봅니다. 강좌란에 올리기 부끄럽습니다만, 처음 시작하시는 분들에게 그런 글이 되었으면 하는 바램입니다.


예전의 기억과 더듬더듬 읽은 문서를 바탕으로 작성한 글이니 조금 틀리고 설명이 빈약하여 어렵게 느껴지지 않을까하는

우려가 있습니다만 가볍게 시작하겠습니다. 그러니 가볍게 읽어 주시고, 틀린 부분은 알아서들 필터하세요~


참고로 Objective C를 만든 분은 Brad Cox라는 분입니다. (설마 잡스가 만들었다고 생각하시는 분들은 없겠죠? ㅋㅋ)

http://www.virtualschool.edu/cox/



* 문서 이력 *

v1 : 최초 작성

v2 : 문구 수정, 오타수정, 메모리관련 추가, 문서이력 추가



* 우선 코딩 기본 규칙 *

  1. 클래스는 대문자로 시작합니다.

  2. 인스턴스 변수는 소문자로 시작합니다. private할 경우 _xxx, __xxx 허용합니다.

  3. 클래스 메소드이건 인스턴스 메소드이건 상관없이 소문자로 시작합니다.

  4. 캐멀 표기법 따릅니다.

어디 정의된 것은 아닙니다만, 제가 이제까지 보면서 느낀 최소한의 규칙입니다.

나쁜 코딩습관이 에러를 만든다는 것은 조엘 아저씨의 주옥같은 명언집을 언급하지 않더라도 아실겁니다.



1. 최상위 클래스

   NSObject입니다. NSProxy도 있지만 우선 무시하세요.

   자신만의 클래스를 만들 때는 최소한 NSObject에서 상속을 받아야 합니다. (무조건 그렇게 하세요.)



2. 상속, 클래스변수, 연산자 오버로딩

   다중상속을 지원하지 않습니다.

   클래스 변수를 지원하지 않습니다.

   연산자 오버로딩을 지원하지 않습니다.

   아규먼트 오버로딩도 지원하지 않습니다.



3. id, self, super, nil, @""

   id는 객체를 가르키는 포인터입니다. void *와 같습니다.

   self는 자신을 가르키는 포인터입니다. java의 this와 같습니다.

   super는 현 객체가 상속한 상위 객체입니다. java의 super와 같습니다.

   nil은 객체가 없음을 나타내는 객체 포인터입니다. NULL은 C의 그것입니다.

   c style의 스트링은 "하하" 처럼 표기하고, 유니코드 스트링은 @"하하" 처럼 표기합니다.


   * 참고로 메소드의 기본 리턴 타입은 id입니다. 아래에서 보겠습니다만,

     - (id) sayHello;

     - sayHello;

   위 둘은 같습니다. 즉, 명시하지 않으면 기본으로 객체타입을 리턴하는 것으로 간주합니다. 요즘은 첫번째를 많이

   사용하더군요.



4. 객체 생성

   MyObject *className = [[MyObject alloc] init];

   alloc은 클래스 메소드입니다. init은 인스턴스 메소드입니다.

   alloc은 메모리를 준비합니다. init은 인스턴스 변수를 초기화합니다.

   init은 기본 초기화 메소드입니다. 이런 초기화 메소드를 만들 때는 반드시 initXXX로 만드세요. (NSObject 참고) 

   만약 다른 객체를 생성해서 리턴하는 것이라면 가능한 createXXX로 만드세요.


   

5. 메세지 보내기

   오브젝티브씨는 "["로 시작하고, "]"로 닫고, 문장의 끝은 ";"로 마무리를 합니다.

   또한 표현을 '객체에 메세지를 보낸다'고 합니다. 함수호출 이런 말 제발 안봤으면 합니다.

   [myObject draw];



6. 메세지 중첩하여 보내기

   어떤 메소드의 결과값(리턴값)이 객체일 경우 메세지를 중첩해서 보낼 수 있습니다.

   즉, myObject 에 draw라는 메세지를 보냈을 경우, 그 리턴값이 myObject라면

   [[myObject draw] transform];

   처럼 보낼 수 있습니다. 3중, 4중으로 보내도 됩니다...

   위에 것은

   [myObject draw];

   [myObject transform];

   과 같습니다. 처음엔 생소하겠지만, 자주 보면 익숙해집니다.



7. 메세지 인자

   메세지 인자는 ":"로 구별합니다. 또 ":"앞에 좀 더 분명하게 하기 위해 메세지 구별자를 추가할 수도 있습니다. 

   [myObject drawWithX:pointX withY:pointY];

   [myObject drawWithX:pointX :pointY]; //위의 것보다는 pointY가 무엇을 의미하는지 알기 힘들죠.

   [self show]; // 자기 자신에게 보내는 메세지입니다.


   

8. import

   헤더를 인클루드 할 때는 C의 include보다는 import를 사용하세요. 이중으로 include되더라도 허용케 합니다.

   물론 C쪽 헤더는 include도 사용합니다.



9. 클래스 선언

   *. "클래스이름.h" 로 파일을 만듭니다. (클래스 이름과 달라도 상관은 없습니다. 그러나 구별을 어렵게 합니다.)

   *. Foundation이나 UIKit을 임포트하세요. 모르겠다면 UIKit을 임포트하세요.

   *. "@interface 클래스네임 : 상위클래스" 로 시작하세요. 

   *. 그 아래 { } 사이에 인스턴스 변수를 선언하세요.

   *. "+ (리턴형) 클래스 메소드;" 로 클래스 메소드를 선언하세요.

   *. "- (리턴형) 인스턴스 메소드;" 로 인스턴스 메소드를 선언하세요.

   *. "@end"로 닫습니다.

   

   #import <Foundation/Foundation.h> // 또는 #import <UIKit/UIKit.h>

   @interface MyName : NSObject 

   {

      NSString *name;

   }

   + (MyName*) newInstance; //또는 +(id) newInstance;

   - (id) initWithName:(NSString *)name;

   @end

   


10. 클래스 구현

   *. "클래스이름.m" 로 파일을 만듭니다.

   *. "#import 클래스이름.h" 로 클래스 선언을 임포트합니다.

   *. "@implementation MyName"으로 구현을 시작합니다.

   *. "+ (리턴형) 클래스메소드 {...}" 에서 구현합니다. 

   *. "- (리턴형) 인스턴스메소드 {...}" 에서 구현합니다.

   

   #import "MyName.h"

   @implementation MyName

   + (MyName*) newInstance

   {

      // 여기에 구현을 합니다. 아래는 기본 패턴입니다.

      return [[MyName alloc] initWithName:nil] autorelease];

   }

   - (id) initWithName:(NSString *)name

   {

      // 여기에 구현을 합니다. 아래는 기본패턴입니다.

      if (self = [super init]) {


      }

      return self;

   }

   @end



여기까지가 기본적인 사항입니다. 어렵나요? 약간 낮설다는 기분이지 이해하고 그럴 만한 그런게 없을 겁니다.

그럼 조금은 이해가 필요한 것들에 대해 이야기해보겠습니다.



11. 객체의 메모리 관리; alloc/dealloc/release/autorelease

   메모리 관리는 좀 복잡합니다. '생성한자 또는 명시적으로 소유하겠다고 선언한 자가 소거의 책임이 있다.' 라고

   정의하면 될 듯 합니다. 이것을 OWNERSHIP이이라고 합니다. 가비지 콜렉션을 지원하지 않고, 개발자가 관리하는

   구조이며, retainCount를 사용하는 메커니즘입니다. retainCount가 0이면 소거될 수 있습니다. 

   (바로 소거되지 않을 수도 있습니다. 이런 메모리 관리 기법은 인터넷을 찾아보시고...)

   

   객체의 생성은 alloc, copy가 있습니다. 어떤 객체를 생성/복사하지 않고 소유하고자 할 경우 retain이란 메세지를

   보냅니다. alloc, copy, retain 메세지를 보내면 리테인카운트는 1씩 증가합니다. 그 반대는 release 메소드입니다.

   리테인카운트를 1씩 감소합니다. alloc, copy, retain시 소유권이 생긴다는 것을 반드시 기억하세요!!!

   

   어떤 객체가 가진 인스턴스 변수를 소거하고자 할 경우엔 - (void)dealloc; 메소드에서 처리하면 됩니다. 반드시

   끝 날 때는 [super dealloc]; 을 해줘야 합니다.

   - (void)dealloc {

      [myName release];

      [super dealloc];

   }

   

   autorelease는 릴리즈풀에 넣어두고 소유자가 없을 경우나 풀이 소거될때 소거되도록 합니다. 프로그램을 하다보면

   소유자가 불분명해지는 경우가 있습니다. 이 말은 소거를 누가할지 결정하기 힘들다는 말과 같습니다. 그럴 때

   많이 사용합니다. 클래스메소드에서 객체를 생성해 리턴해줄 경우를 생각해보죠. 리턴을 하게되면 이 객체는 누가

   소유 할까요? 네, 아주 잠시 아무도 소유할 수 없는 상황이 발생합니다. (아~ 이해안되더라도 그냥 그렇다고 넘어가시길...)

   이때 소거를 잠시 미루도록 autorelease를 해서 릴리즈풀에 담아둡니다. (릴리즈풀은 애플 문서를 참고하시고, 우선 스킵합니다.)


   몇 가지 예제를 보면서 맛이라도 한번 보겠습니다.

   - (void) memoryTest {

      // 인스턴스 변수일 경우

      myInstance1 = [[NSString stringWithString:@"Hangul"] retain]; // autorelease된 객체

      myInstance2 = [[NSString alloc] initWithString:@"Hangule"];

   

      // 일반 변수일 경우

      NSString *str1 = [NSString stringWithString:@"Hangule"];

      NSString *str2 = [[NSString alloc] initWithString:@"Hangule"];

      NSString *str3 = [NSString stringWithString:@"Test"];

      

      [str2 release];

   }

   

   myInstance1에 autorelease된 객체입니다. stringWithString:으로 생성된 객체는 메소드가 끝나면 소거됩니다. 

   따라서 retain을 해서 소거를 막고, 소유를 합니다.

   myInstance2는 alloc된 객체입니다. 리테인카운트 1이고 인스턴스 변수이므로 객체가 살아있는 동안 남아 있어야 하므로

   release를 하면 안되겠죠.

   str1은 autorelease된 객체입니다. 메소드가 끝나면 소거됩니다. (바로 안될 수도 있음)

   str2는 alloc된 객체입니다. 리테인 카운트 1이고, 메소드가 끝나도 소거되기 위해선 반드시 release를 해줘야 합니다.


   myInstance1에 str3을 어사인하고자할 경우엔 어떻게 하는지 보겠습니다.

   [myInstance1 release]; //릴리즈 카운트 감소. 더이상 own할 필요가 없으니 이제 해방시켜줍니다. 안하면 메로리릭!

   myInstance1 = [str3 retain]; // str3는 지역변수이므로 메소드가 끝나면 사라집니다. 리테인해서 소거를 막습니다.

   

   여기서 myInstance1 = str3; 하는 것과 myInstance1 = [str3 retain]; 하는 것은 엄청난 차이가 있습니다.

   앞의 것은 포인터가 같아지는 것이고, 뒤의 것은 소유(ownership)하는 것이기 때문입니다.


   또 다른 예를 하나 더 보겠습니다. NSArray란 것은 객체 어레이를 담는 콜렉션중 하나입니다. NSMutableArray는 가감을

   할 수 있고, NSArray는 생성된 시점이후에 가감을 할 수 없습니다. Mutable이 붙은 클래스는 동일한 룰이 적용됩니다.

   - (void) someMethod {

    NSMutableArray *mArray = [NSMutableArray array]; 

        NSString *str = [NSString stringWithString:@"Hangul"];

        [mArray addObject:str];

      

       [mInstanceArray release]; // 이전 인스턴스변수는 새로운 값을 소유하기 전에 반드시 릴리즈시켜야 합니다.

       myInstanceArray = [mArray retain];

   }


   이 경우 메소드가 끝나면 str은 없어지겠죠? 그럼 mArray에는 str이 어떻게 될까요?

   네... 바로 ownership을 생각해야 합니다. mArray는 str을 담고 있어야 하므로 addObject:할때 str을 retain하게

   됩니다. 따라서 메소드가 끝나도 str은 없어지지 않습니다. 즉, 자기가 쓰겠다고 했으니 retain을 하는 겁니다.

   따라서 mArray가 소거될때, 또는 str이 제거될때 release가 불리는 것을 생각할 수 있을 겁니다. 그럼 retain해서

   1증가하고, release해서 1 감소하니 결국 소거가 될 수 있는 것입니다. 어렵다구요? 만약에 자신이 NSArray를

   만든다고 생각을 해보세요. 그러면, add한 객체를 어떻게할지... 또 내가 만든 클래스에서는 어떻게 객체를 소유할지...

   바로 알아챘을 거라 봅니다.


   마지막으로 하나만 더 들어보겠습니다. (초보단계는 아니지만, 개념을 확실히 이해하시라고 추가합니다.)

   여기 MutableArray *myMutableArray가 있습니다. 첫번째 것을 꺼내 마지막으로 넣고자 할때 어떻게 해야할지

   생각해보겠습니다.


   - (void)moveToLast {

     id firstObject = [myMutableArray objectAtIndex:0]; // 객체 포인터 얻기

     

     [firstObject retain]; // 메모리에서 소거되지 않도록 소유하고, (+1)

     [myMutableArray removeObjectAtIndex:0]; // 어레이에서 제거한다. 이때 어레이는 제거되는 객체를 release한다. (-1)

     [myMutableArray addObject:firstObject]; // 어레이 마지막에 추가한다. 이때 어레이는 객체를 retain한다. (+1)

     [firstObject release]; // 이제 필요가 없으니 소유권을 버립니다. (-1)

   }


   원리는 똑~ 같습니다. 즉, 사용할 것이면 리테인을 하라는 겁니다!

   즉, 단순히 제거할 것이 아니라 다시 사용할 것이므로 retain을 해서 잠시 소유해야 합니다.

   그리고 소유할 필요가 없으면 release를 합니다.


   만약 [firstObject retain]; 을 하지 않았다면 위 코드가 문제없이 수행될 수 있을까요?

   정답은 그럴 수도 있고 아닐 수도 있다입니다. 


   id firstObject = [myMutableArray objectAtIndex:0];

   [myMutableArray removeObjectAtIndex:0];

   [myMutableArray addObject:firstObject];


   즉, 이렇게 해도 문제가 없을 수도 있습니다. 어떤 상황에서 그럴까요? 

   네~ 그렇습니다. firstObject 객체를 누군가 소유하고(즉, 리테인카운트가 2이상) 있다면 removeObject를 할때

   release를 보내더라도 소거가 되지 않겠죠. 그래서 이 코드는 상황에 따라 제대로 돌았다가 안 돌았다가 하는 알 수

   없는 미치고 팔짝뛰는 상황이 만들어 집니다. 또 release를 하더라도 바로 소거되지 않을 수도 있기 때문에, 설령 다른 객체가

   소유를 하지 않더라도 왔다갔다 하는 상황이 나올 수도 있습니다. (이쯤되면 개발자는 온 게시판에 도배질을 시작합니다… ㅋㅋ)


   이런 상황은 소유개념에 대한 이해가 없으면(또, 살짝 주의를 게을리하면) 충분히 발생할 수 있습니다.

   이것이 리테인카운트 메커니즘을 사용하는 메모리 관리시스템의 약점 중 하나입니다.

   어느 곳 하나 삐긋하면 메모리에 구멍이 나고, 매직스런 상황이 연출된다는...


   암튼, 소유(retain, ownership)라는 말을 수도 없이 지긋지긋하게 했으니, 이제 중요한 포인트가 뭔진 아시겠죠?

   그래도, 메모리 관련해서는 반드시 애플의 문서를 읽기를 권합니다.

   

   참고로, 원래 오브젝티브씨란 언어에 이런 개념이 있던게 아니랍니다. OPENSTEP이후부터 이런 개념이 추가되었습니다.

   그게 없던 시절(NeXTSTEP) 오브젝티브씨는 C와 똑같이 malloc/free를 사용했습니다.



12. SEL 타입, @selector()

   오브젝티브씨에서 메소드 포인터를 SEL이라는 타입을 쓴다고 이해하면 됩니다.

   그 SEL 타입을 만들 때, @selector()라는 것을 사용합니다.

 

   SEL method = @selector(drawWithX:pointX);


   SEL은 어떤 객체가 불리워질지를 정의하지 않습니다. 요건 오브젝티브씨의 런타임을 보면 이해할 수 있는데, 우선은

   어떤 객체에 메소드를 어떻게 부르는지만 살펴보겠습니다.

   [myObject performSelector:@selector(drawWithX)]; // 인자가 없을 경우

   [myObject performSelector:@selector(drawWithX:) withObject:floatObject]; //인자는 반드시 객체여야 함

   [myObject performSelector:@selector(drawWithX:) withObject:floatObject afterDelay:0.1f]; // 0.1sec 뒤에 실행

   

   마지막 것은 예전에 없던건데 추가된 겁니다. 폰의 특성상 약간 늦게 시작해야 빠른 듯 느껴지는 경우가 있습니다.

   그럴때 유용할 수 있습니다.

   

   만약 myObject에 해당 메소드가 없으면? 에러입니다. 그럼 어떤 메소드를 받을 수 있는지는 어떻게 알아내냐면

   - (BOOL)responseToSelector:(SEL)aSelector; 를 사용합니다. 아래 delegate를 한번 보세요.



13. delegate, dataSource

   이건 패턴의 하나인데, 구태여 소개하는 것은 아예 delegate라고 못 밖아서 인스턴스 이름으로 쓰기 떄문입니다.

   말 그대로 대행자입니다. 내용은 간단합니다. 어떤 객체가 어떤 일을 하고자 할 때나 끝났을 때 대행자를 가지고 있을

   경우 그 대행자가 수행할 수 있도록 메세지를 보내는 것입니다. (메소드 내에 Will,Did,Should가 들어가 있다면

   대부분 딜리게이트 메소드입니다.) 내부적인 구현 방법을 보면 이해하기 쉽습니다. 


   if ( delegate && [delegate responseToSelector:@selector(doOther:) ) 

      [delegate performSelector:@selector(doOther:)]; //performSelector 메소드가 SEL을 호출합니다.


   즉, 객체의 변수로 delegate라는 객체가 있고, -doOther라는 메소드를 받을 수 있으면 메세지를 보내는 식입니다. 


   비슷한 것으로 dataSource도 있습니다. 마찬가지로 패턴의 하나인데, 직접적으로 dataSource라고 사용하고 방법도

   delegate와 같습니다. 테이블, 피커등에 데이터를 전달할 경우 많이 사용합니다.

   

   delegate, dataSource의 개념에 해당하는 인스턴스 변수를 어떻게 짓던 상관은 없지만, 가급적 맞추는 것이 좋습니다.

   그래야 남들도 이해하기 쉽습니다. 

   

   또 하나, delegate나 dataSource를 지정할 때는 그 객체를 retain하지 않는 것이 보편적입니다.

   단순하게 delegate = otherObject; 처럼 합니다. 이를 weak reference한다고 하고 소멸의 책임이 없습니다.

   그러나, delegate = [otherObject retain]; 이렇게 하면 소멸의 책임을 집니다. 

   즉, -dealloc 에서 [delegate release];를 해줘야 합니다.


   

14. category

   카테고리는 메소드의 묶음입니다. 위에서 *.h에 메소드를 정의하는 방법을 배웠습니다. 그것이 기본 카테고리입니다.

   즉, 오브젝티브씨는 메소드를 묶음 단위로 표기할 수 있고, 또한 기존의 클래스에 묶음으로 메소드를 더할 수도 있습니다. 

   여기서 기존의 클래스에 메소드를 더할 수 있다는 것이 중요합니다. 예들들어 보겠습니다.

   

   NSString이란 클래스는 스트링을 다루는 기본 클래스입니다. 이 클래스에 한글이 있는지 없는지를 리턴하는 메소드를

   추가하고 싶을 경우 대부분은 서브클래싱을 생각하게됩니다. 그러나, 오브젝티브씨는 서브클래싱없이 메소드를 더합니다.

   방법은 클래스의 생성과 매우 유사합니다. 다만, 수퍼클래스 이름 대신 메소드 묶음 이름(카테고리 이름)을 "(...)"

   안에 적습니다.

   

   @interface NSString (MyNSStringAddition)

   - (BOOL)hasHangul;

   @end

   

   이렇게 선언하고, 구현은 interface대신 implementation을 사용하면 됩니다.

   그리고 사용은 아래처럼 합니다.

   

   NSString *myString = [[NSString alloc] initWith:@"Hangul 한글"];

   BOOL hasHangul = [myString hasHangul];


   자바스크립트에서 prototype으로 기존 클래스에 메소드를 추가하는 것을 본적 있는 분들은 이해가 빠를겁니다.

   

   두개의 룰이 필요합니다. 기존의 메소드 이름과 겹치지 말아야 한다는 것과 카테고리명이 유일해야 한다는 것이 바로

   그것입니다. 메소드의 묶음이기 때문에 인스턴스 변수를 가지는 것이 아닙니다. 따라서 별도의 인스턴스가 추가되는

   상황이 아니라면 서브클래싱 하지 않고 메소드만 추가하는 카테고리가 훨씬 합당합니다. 또한 메소드를 구조적으로 묶어

   주므로써 코드 관리를 용이하게 하는 장점도 있습니다.

   

   카테고리는 다른 파일로(별도 헤더파일과 구현파일) 만들어 사용하는 경우가 많고, 구태여 헤더파일에 넣어 API를

   공개시키지 않고 싶을 경우 (즉, 프라이빗하게 사용하고자 할 경우), *.m파일에서 정의하여 사용하기도 합니다.

   또 예들 든것처럼 기존 클래스에 메소드가 없는 경우에도 사용합니다. (기존 클래스의 메소드를 완전히 변경할 수도

   아예 클래스를 변경할 수도 있습니다. 메소드스위즐링, 포우져라고 하는데 넘어가도 좋습니다.)



15. protocol

   프로코콜은 주고 받을 수 있는 메세지를 규약하기 위한 것입니다. 자바의 인터페이스와 흡사합니다. 

   프로코콜을 정의하는 방법은 다음과 같습니다.

   

   @protocol 프로코콜이름 <적용대상 클래스 이름>

   

   예제를 볼까요?

   

   @protocol DoYouLikeMe <NSObject>

   @required //이하 메소드는 반드시 구현해야 하는 메소드입니다.

   - (BOOL)canAccept:(NSString *)otherName;

   @optional //꼭 할 필요는 없습니다.

   - (BOOL)doYouLikeIt:(NSString *)boysName;

   @end

   

   어떤 클래스가 프로토콜을 구현을 하고 있다고 컴파일러에게 알리고자 할 경우엔,

   @interface MyName : NSObject <프로코콜이름, 프로토콜이름,...>

   이렇게 합니다. dataSource 패턴에 적절하겠죠?

   

   그럼 어떻게 객체가 프로코콜을 정의하고 있는지 알 수 있을까요? 역시 NSObject에서 

   - (BOOL)conformsToProtocol:(Protocol *)aProtocol; 를 사용하면 됩니다. 아래처럼 사용합니다.

   if ([receiver conformsToProtocol:@protocol(MyXMLSupport)]) {

 //your code here!   

   }

   

   또 어떤 객체가 프로코콜을 사용하고 있다는 것을 알려주고자 할 경우,

   MyObject <프로코콜이름> *myObject;

   처럼 사용합니다.


   informal, formal protocol이란 이야기도 보게 될겁니다. 위에 DoYouLikeMe같이 정의하는 것을 formal이라하고

   NSObject에 카테고리처럼 정의하는 것을 informal이라고 합니다. formal은 컴파일러가 체크를 할 수 있지만, informal은

   컴파일러가 체크를 할 수 없습니다. informal은 delegate methods를 구성할 경우 많이 사용합니다. 아래를 보면

   카테고리와 흡사하게 정의됨을 볼 수 있을 겁니다. 대부분 NSObject에 바인딩되고, 구현하지 않는다는 점에서 다릅니다.

   (프로코콜이란 것은 적용하는 객체가 구현하는 것이니 당연한 이야기겠죠.)

   

   @interface NSObject (MyProtocol)

   - (id)makeGirlfriend:(NSString*)name;

   - (NSArray *)girlsLikeMe;

   @end

   

   informal 프로토콜은 카테고리와 약간 구별하기 애매할 겁니다. 구현을 하느냐 안하느냐로 우선 구분하세요.

   뭐 처음부터 이해하려고 하지 않아도 됩니다. (그래서 설명을 빼려고 했습니다만,...)



16. get/set 그리고 property

   오브젝티브씨에서는 get/set에 대한 규정이 자바처럼 엄격하질 않습니다. 대부분 setXXX는 쓰지만, getXXX 보다는

   xXX로 씁니다. 이런 get/set을 보다 쉽게 만든 것이 바로 Objective C 2.0에 포함된 property이고, "." 로 객체의 

   변수에 접근할 수 있게 합니다. 사용방법은 간단합니다.


   헤더 파일엔 다음처럼 선언합니다.

   @property (nonatomic, retain) NSString *name; //객체를 쓰레드 세이프하지 않게하고, retain을 하라는 뜻

   @property (nonatomic, readonly) NSString *myGirl; // get만 할 수 있다는 뜻.

   nonatomic은 스레드로 접근할 때 락을 하는냐 마느냐입니다. 폰에서는 대부분 퍼퍼먼스의 이유로 nonatomic으로

   사용하라고 합니다.

   

   구현파일(*.m) 파일엔 @implementation 아래에

   @synthesize name, myGirl;

   처럼 하면 자동적으로 get/set 이 구현됩니다. (컴파일 타임에 생성된다는 의미)

   

   사용은...

   myObject.name = @"hehehe";

   NSString *herName = myObject.myGirl;

   

   처럼 "." 표현을 사용합니다. 코드량을 많이 줄여주고, 잘못 사용하면 메모리 릭이 날 수 있습니다. 따라서 애플 문서를

   반드시 참고하세요.


   

17. private, protected, public...

    @private, @protected, @public 으로 표기하고 그 이하의 변수가 포함됩니다.

    

    다만, 메소드에는 이런 스코프 제한이 없습니다. 즉, 헤더에 보여지는 것은 모두 public입니다.

    private한 경우 "_"를 붙여 개발자 상호간에 이해하는 컨벤션을 쓴다던가, 또는 *.m파일에 카테고리를 사용해서

    헤더에 노출을 시키지 않는 방법을 씁니다. (물론 클래스 덤프하면 다 보입니다.)

    

    더불어 클래스 변수도 없습니다.

    *.m파일내의 @implementation 안에서 static으로 선언해 쓰거나 해야 합니다. 상속받은 객체에서 보기를 원한다면

    extern 선언을 해야 합니다.



18. @class, @protocol

예제코드를 보다보면 헤더에 "@class XXXX;"식의 코드를 볼 수 있습니다. 이것은 XXX라는 클래스가 있다는 것을

컴파일러에게 알려주는 역할을 합니다. 마찬가지로 @protocol도 같은 역할을 합니다. 물론 헤더파일에 해당 클래스를

임포트시켜도 됩니다. @class는 컴파일러나 링커가 임포트보다는 좀 더 쉽게 처리할 수 있게 한다라는 정도만 알면

되겠습니다.



이 정도면 기본 문법은 대충 다 본 셈인듯합니다.

마지막으로 몇 가지 아이폰을 개발하면서 알아두면 좋은 것들을 이야기해보고자 합니다.



19. 디자인 패턴

    첫번째로 MVC 모델입니다. 관련된 내용은 인터넷에 수 많은 글들이 있으니 생략하겠습니다. 

    두번째는 target/action 패러다임을 사용합니다. (아래 22. 참고)

    세번째는 살펴본바와 같이 delegate, dataSource 패턴을 사용합니다.

    네번째는 노티피케이션입니다. 어떤 일이 일어난 것에 관심이 있을 경우 노티피케이션센터에 관심이 있다고 등록을 합니다.

    어떤 객체가 노티피케이션을 보내면 센터에 등록된 모든 객체가 반응할 수 있게 합니다. 일종의 메세지 브로드캐스팅

    이라고 보시면 됩니다.

    다섯번째는 late loading입니다. 불필요한 객체나 리소스를 처음부터 생성하지 말고, 가능하면 필요할 때 생성/로드

    하라는 것입니다. 여기서 필요를 결정하는 것은 개발자입니다. 즉, 반드시가 아닙니다.

    

    이상이 아이폰 개발에서 염두해두실 만한 고전적인(?) 주요 패턴으로 보시면 됩니다.



20. 프레임웍 구조

    오브젝티브씨의 기본 프레임웍은 Foundation이라고 합니다. 문자, 문자셋, 어레이, 집합, 딕셔너리, 넘버, 날짜,

    로케일등등이 모두 여기에 포함되어 있습니다. 화면과 관련된 것은 아이폰에서는 UIKit이라고 하고, OS X에서는 AppKit

    이라고 합니다. 물론 스트링은 유니코드를 기반으로 합니다. 한글 인코딩은 EUC-KR(5601-1987), MS949, KSC5601_87,

    KSC5601_92_Johab, Mac Korean(EUC-KR과 같으나 CRLF가 다름) 등을 지원합니다.

        

    참고로 Objective C의 프레임웍/런타임을 통칭해서 Cocoa라고 부릅니다. NeXT사가 애플에 합병되면서 가져온

    프레임웍이고 OPENSTEP이란 스펙에 따라 만들어졌습니다. Mac 고유의 API는 수정되어 Carbon이라고 불립니다.

    CFxxx 이렇게 시작하는 것들이 그것들이라고 보시면 됩니다. (Carbon을 이런 함수들로만 보는 것은 무리가 있습니다만,

    우선은 그렇다라고 생각해주세요.)


    

21. firstResponder, File's owner

    이것은 언어적인 특성이라기 보다는 MVC를 구성하면서 파생된 개념으로 보시면 됩니다.

    firstResponder은 OS X에서는 첫번째 키보드나 마우스 이벤트를 받는 객체입니다. 아이폰에서는 키보드나 마우스란

    것이 없으니 터치만 해당됩니다. 반드시 그런 것은 아니지만, 우선 아이폰에서는 화면상에서 키보드가 나타나고 커서가

    보이는 것이 바로 firstResponder 객체라고 보시면 됩니다. 


    예를 하나 들어보겠습니다. 만약 메뉴에서 copy&paste를 구현한다고 할때, -copy; -passte; 메소드를 보내야할 겁니다.

    자~ 문제입니다. 어떤 객체에 보내야 효율적인 코딩이 될까요? 네 맞습니다. 바로 firstResponder에 보내는 겁니다.

    

    File's owner는 인터페이스빌더(약칭, IB)에서 사용하는 개념입니다. 코코아에서는 MVC중 V와 C를 냉동보관했다가

    어플리케이션이 필요할 때 녹여서 메모리에 올리는 기법을 사용합니다. 물론 코드만 가지고 어플리케이션을 짜도

    되지만, 툴을 사용하면 코드량을 획기적으로 줄일 수 있다는 장점이 있습니다. 대략 UI를 잡은 다음에 코드로 세밀하게

    다듬는 식의 방법을 많이 사용합니다. (OS X에서 애플의 어플리케이션을 보면 이런 방법을 많이 사용합니다.)

    

    그 냉동된 파일을 NIB(NeXT Interface Builder) 이라고 하는데 요즘은 XIB(확장자 *.xib)라고도 합니다. IB를

    가지고 화면을 꾸미고 컨트롤과 연결한 후 실제 프로그램에선 NIB를 로딩해야합니다. 이 때 그 NIB의 소유자를

    File's owner라고 합니다. 대부분 MVC중 C에 해당하는 것들이 File's owner가 됩니다. 즉, 컨트롤과 뷰간에 객체를

    인식(outlet)하고 메세지를 보내고자 할 경우, 컨트롤 객체가 생성이 되어 있어야 할 것입니다. 바로 그것이 

    File's Owner가 됩니다.



22. outlet, target, action, connection

    오브젝티브씨는 이벤트 드리븐이 아니라 메소드(메세지) 드리븐이라는 말을 합니다. 어떤 객체에 이벤트가 발생했을 때

    타 객체에 메세지를 보내는 방식으로 일을 처리합니다. 처리할 이벤트를 등록해서 처리하는 방법이 아닙니다.

    

    NIB파일은 위에서 설명한 대로 MVC중 V와 C를 녹여(시리얼라이즈) 해 놓았는데, 컨트롤이 화면의 객체를 알아야 할 필요가 있습니다.

    그래야 메세지를 보내 속성을 바꾸거나, 텍스트를 뿌리거나, 슬라이드를 이동하거나 사이즈를 줄이거나 할 수 있을 겁니다.

    IB에서는 이를 outlet이라고 합니다. 또한 컨트롤(버튼,슬라이더등)이 움직였을 때 컨트롤이 반응할 수 도 있어야 합니다.

    

    이처럼 메세지를 받는 쪽을 target이라고 하고 보내는 메세지를 action이라고 합니다. 또 IB에서 outlet을 정하거나,

    메세지를 보내는 것을 커넥션을 맺는다고 합니다.(control+drag해서)

    

    한참 안봐서 모르겠습니다만, OS X에서는 action메소드는 항상 "- (IBAction)actionMethod:(id)sender;"처럼

    정의합니다. iPhone에서는 "- (IBAction)actionMethod;"처럼 정의해도 인터페이스빌더가 알아챕니다.

    

    IBAction은 void 형이고, 인터페이스빌더가 액션메소드임을 알아내기 위한 예약어라고 보시면 됩니다.

    IBOutlet은 인터페이스 빌더가 outlet을 구별하기 위해 사용하는 예약어라고 보면 됩니다.

    


자료출처 : 맥부기 카페([완천초급] 오브젝티브씨 시작하기...)

http://cafe.naver.com/mcbugi/29965

        switch(CFByteOrderGetCurrent()){

            case CFByteOrderUnknown:

                NSLog(@"UnKown");

                break;

            case CFByteOrderLittleEndian:

                NSLog(@"LittleEndian");

                break;

            case CFByteOrderBigEndian:

                NSLog(@"BigEndian");

                break;

        }

'Tips & Tech > Objective-C' 카테고리의 다른 글

Objective-c 상속  (0) 2012.02.27
Objective-c 시작하기  (0) 2012.02.27
const char* buffer > NSData 변환방식.  (0) 2012.02.27
[iPhone]개발 및 디버깅 팁 10 가지  (0) 2012.02.27
[iPhone]메모리 관리  (0) 2012.02.27
<meta charset="utf-8" /><meta charset="utf-8" />

* const char* 형식인 buffer 데이터를 NSData 로 변환한 후 파일에 저장.

filePath : 저장될 파일 이름 및 경로

endcoding 타입은 buffer에 저장된 데이터의 타입을 확인한 후 설정해야 한다.


NSString *stringData = [[NSString alloc] initWithCString:buffer encoding:NSUTF8StringEncoding];

NSData *bufferData = [stringData dataUsingEncoding:NSUTF8StringEncoding];

[bufferData writeToFile:filePath atomically:YES];

[stringData release];


//=========Translate_Formats=========================

const char *cStringfile  = [inputFile  cStringUsingEncoding:1 ];    // transfer NSString to Cstring

const char *utfString2 = [myString2 UTF8String];                    // NSstring --> UTF8String

data1 =     [NSData dataWithBytes: utfString2  length:7];        // UTF8String --> NSData


NSString *  str33=  [NSString stringWithUTF8String:cBuffer];   // buffer --> string

NSString *  OutputString;

OutputString =  [NSString stringWithFormat:@"%s",dBuffer];    // buffer -> string


[myData getBytes:aBuffer  length:20];                                  // data --> buffer

[data1    getBytes:bBuffer  length:7];                                    // NSData --> buffer

// file --> data   reads every byte into myData

NSData *myData = [NSData dataWithContentsOfFile:thePath]; 

unsigned char            aBuffer[20];

NSMutableString *   timeString;

// start of string -> buffer

timeString =  [NSString stringWithFormat:@":%3.2f:%@: ",timeHere, PictFile];

utfString  =   [timeString UTF8String];                           // NSstring --> UTF8String

data1 =   [NSData dataWithBytes:utfString length:timeStringLength]; // UTF8String --> NSData 

[data1 getBytes:eBuffer  length:timeStringLength];                          // data --> buffer

'Tips & Tech > Objective-C' 카테고리의 다른 글

Objective-c 시작하기  (0) 2012.02.27
바이트 오더 형식 확인하기 위한 방법.  (0) 2012.02.27
[iPhone]개발 및 디버깅 팁 10 가지  (0) 2012.02.27
[iPhone]메모리 관리  (0) 2012.02.27
[TCP]한글깨짐현상.  (0) 2012.02.27

1. printf, NSLog, CFShow 사용하여 로그 찍어 봅니다. 특히 CFShow 는 core foundation object 의

내용을 출력해 줍니다.



2. executable 에 arguments variables 로 NSZombieEnabled = YES 로 설정하면 좀더 많은 정보

를 보여줍니다. 단  release 모드에서는 반드시 제외해야합니다.



3. 크래쉬 리포트 확인하기, iTunes 가 수집한 크래쉬 리포트를 볼 수 있습니다.

~/Library/Logs/CrashReporter/MobileDevice/<device name>



4. 컴파일러 디렉티브(compiler directives) 를 사용하여 iOS 버전 별 검사를 할 수 있습니다. 

- #if TARGET_IPHONE_SIMULATOR

- code....

- #else

- code...

- #endif

- #ifdef _USE_OS_3_OR_LATER

- #import <MapKit/MapKit.h>

- #endif

- #if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000

- pre 3.0 code...

- #else

- 3.0 code...

- #endif



5. 메모리 누수 등을 Instruments 활용하여 점검할 수 있습니다. 참고할 만한 문서는 아래와 같습니다. 


http://blog.naver.com/PostView.nhn?blogId=mirnae&logNo=100102037283&redirect=Dlog&widgetTypeCall=true/


특히 Xcode 4 에서는 product -> profile 을 실행하면 자동으로 instruments 가 실행되면서 점검

가능합니다.



6. 시간이 지남에 따라 어떤 동작을 하는지를 검사해 보려면, 컴퓨터 시간을 바꾸기만 해도 시뮬레이터

에서 알아서 바뀐 시간을 인식합니다.



7. #pragma mark 를 이용하여 소스 코드를 정리하며 보면 더 편리합니다.



8. uncrustify 라는 공개 유틸을 사용하면 Objective C 코드 정렬 (indentation) 을 자신이 원하는

대로 사용하여 볼 수 있고, Xcode 에서도 단축키 지정으로 적용할 수 있습니다. 구글에서 uncrustify

objective c 라고 치면 사용법이 나옵니다.  제가 참고한 문서는 아래와 같습니다. 


http://blog.carbonfive.com/2011/03/10/code-formatting-in-xcode-4/




9. ingredients 라는 공개 유틸을 사용하면 Xcode 4 의 기본 도움말 보다 메소드, 클래스 등을 더

편리하게 볼 수 있습니다.  구글에서 ingredients xcode 라고 치면 사이트와 설명을 찾을 수 있습

니다.  제가 참고한 문서는 아래와 같습니다. 


http://fileability.net/ingredients/

http://kuoi.com/~kamikaze/read.php?id=300




10. #ifndef GCC_OPTIMIZATION_LEVEL  지시자로 로 디버그 모드에서만 NSLog 함수를 사용할 수 

있습니다. Xcode 는 Visual Studio 와는 달리 DEBUG  와 같은 컴파일러 변수가 기본으로 지정되어

있지 않습니다. (#ifdef 가 아니라 #ifndef 입니다!) 


*자료출처 : 맥부기 카페(http://cafe.naver.com/mcbugi/134158)

+ Recent posts