[Objective-C] @class 활용

@class 명령을 사용하면 클래스를 직접 정의하지 않으면서 클래스 이름만 선언할 수 있다. (이를 forward declaration 이라 한다.) 즉, @class 명령으로 선언한 클래스는 실제 클래스의 @interface에 선언된 내용을 컴파일하지 않더라도 변수로 선언하고 포인터를 사용할 수 있다.

@class로 선언한 클래스는 포인터로만 참조만 할 수 있을 뿐 클래스의 기능(메소드, 인스턴스 변수 등)을 사용할 수 없다.

예시를 통해 @class를 활용하는 법을 알아보자.

#import "Vehicle.h"
@class Engine;
@class MoonRoof;
@class Radio;

@interface Car : Vehicle{

Engine * engine;
MoonRoof *moonRoof;
Radio *radio;

}

-(void)startEngine;
-(void)stopEngine;
-(void)tuneRadio;

@end

일반적으로 클래스 이름을 사용하려면 컴파일러가 미리 알고 있어야 한다. 이를 위해 #import 구문으로 클래스 정의부 전에 클래스에서 사용할 외부 클래스를 컴파일러에게 알려준다. 즉 @interface 내에서 참조하는 클래스에 대해 각각 #import 구문을 선언해 헤더 파일을 불러와야 한다.

작은 규모의 프로젝트에서는 #import 로 헤더파일을 불러오는 게 컴파일러 입장에서 큰 일은 아니다. 그러나 큰 프로젝트에서는 @interface에서 사용하는 클래스가 다른  클래스를 참조하는 일이 연쇄적으로 생길 수 있다.  이 경우 #import 를 통해 불러와야 하는 클래스의 헤더파일이 많아지게 되고, 많은 헤더파일을 불러와야 하는 컴파일러에게 이 상황은 부담이 된다.

이때 컴파일러의 부담을 때에 따라 덜어줄 수 있는데 @class 명령을 사용하면 된다. 코드를 살펴 보자.

#import "Vehicle.h"
@class Engine;
@class MoonRoof;
@class Radio;

@interface Car : Vehicle{

Engine * engine;
MoonRoof *moonRoof;
Radio *radio;

}

-(void)startEngine;
-(void)stopEngine;
-(void)tuneRadio;

@end

Car 클래스를 사용하는 외부 클래스는 3개의 메소드만 알면 되지 Engine, MoonRoof, Radio 클래스에 대해서는 알 필요가 없다. (protected 로 선언된 변수는 알 수도 없다.)

만약 Engine, MoonRoof, Radio 클래스가 각각 10개의 클래스를 참조하고 있고 모두를 #import 로 선언하고 있다고 가정을 하자. 위 예시에서 Engine, MoonRoof, Radio 를 #import 로 선언했다고 하면 Car 클래스의 헤더 파일이 로딩될 때 Engine, MoonRoof, Radio 클래스 내에서 #import 로 선언된 모든 헤더파일이 불려올 것이다.

위와 같은 경우  Car 클래스를 사용하는 데 Engine, MoonRoof, Radio 클래스의 내용을 알 필요가 없으므로, @class 명령을 이용하여 컴파일러가 Car 클래스의 헤더 파일을 로딩할 때 Engine, MoonRoof, Radio 에 참조된 모든 헤더파일을 로딩하지 않도록 할 수 있다 . 물론 Car 클래스의 구현부(implementation)에서는 Engine, MoonRoof, Radio 의 기능(메소드, 인스턴스 변수 등)을 이용하려면 각 클래스를 #import 해야 한다.

정리하면 슈퍼클래스, public 객체, 메소드의 반환값으로 반환되는 객체에 대해서는 #import 로 헤더파일을 불러와야 하고, 그 외의 모든 클래스에 대해서는 @interface에서 @class만으로 선언하여 불필요한 헤더파일 로딩을 피하는 것이 좋다.

* Reference : Learn Objective-C for Java Developers

Advertisements
Leave a comment

3 Comments

  1. parkjuram

     /  December 10, 2012

    “정리하면 슈퍼클래스, public 객체, 메소드의 반환값으로 반환되는 객체에 대해서는 #import 로 헤더파일을 불러와야 하고, 그 외의 모든 클래스에 대해서는 @interface에서 @class만으로 선언하여 불필요한 헤더파일 로딩을 피하는 것이 좋다. ” 이 부분 전까지는 이해가 됐는데 막상 결론 부분이 이해가 안돼네요… 가능하시다면 설명좀 부탁드립니다.TT

    Reply
    • 제 지식이 얕아서 설명이 부족했나봅니다.

      @interface 에서 class 및 import 사용에 대한 부분은 이해가 되셨고 마지막 정리부분이 이해 안된다고 하셨습니다. 아마 public 객체, 메소드의 반환값에서 @class 가 아닌 #import 를 써야하는 부분때문이라 생각이 듭니다 .

      실제적으로 코딩을 해보면 @interface 부분에서 단순히 클래스 이름만 들어가는 부분에 대해서는 #import 가 아닌 @class 를 사용해도 컴파일상 문제가 발생하지 않습니다. public 객체 및 메소드 반환값이라 할지라도 말이죠.

      그러나 자신이 정의한 header 파일이 사용되는 측면을 생각해볼 필요가 있습니다. 만약 TestB 가 아래와 같이 @class를 통해 참조가 되어 있다고 가정합니다.

      // TestA.h 파일

      @class TestB;
      @interface TestA

      -(TestB*)returnTestBInstance;

      @end

      이 경우, TestC 클래스에서 TestA 를 #import 하여 사용할 때 TestB 의 public 속성, 메소드를 바로 사용할 수 없습니다. @class로만 참조되었기에 TestB 클래스의 상세 내용을 알 수 없는것이죠.

      #import TestA
      @implementation TestC

      -(void)someMethod{

      TestB *testB = [testA returnTestBInstance];
      // testB 의 속성/메소드를 확인할 수 없다.
      }

      @end

      만약 TestA 에서 TestB를 @class가 아닌 #import 로 참조했다면 TestC 에서는 TestA 를 #import 하는 것만으로 메소드의 반환값인 TestB 를 사용할 수 있습니다.

      이처럼 자신이 정의한 header 파일의 사용자 측면을 고려하여 공개되어지는 클래스에 대해서는 #import 로 정의하는 것을 권장하는 것입니다.

      Reply
    • 생각해보니 위에서 제가 ‘권장’이라는 단어를 쓴게 좀 걸리네요. TestA 에서 TestB 를 @class로 참조하고 TestC 에서 import TestA 외에 import TestB 를 하는 것도 많이 사용되는 것 같습니다. TestC 에서 TestB 를 TestA 보다 먼저 import 했을 경우도 있을 것 같네요.

      참고로 include 와 달리 import 는 동일 헤더 중복 로딩을 방지해준다고 알고 있습니다.

      덕분에 저도 좀 더 이 문제에 대해 생각하게 되었습니다. 감사합니다.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: