클래스의 선언과 정의


컴파일러 지시문

Objective-C 언어는 객체 지향 언어이므로 재사용 가능한 데이터 및 제어를 패키지화 한 템플릿을 제공 할 수 있습니다. 이것을 일반적으로 클래스 라고 부르며, 클래스는 메모리 실체를 생성하기위한 정보입니다.

클래스의 개념은 C 언어의 구조체를 발전시킨 것으로, 구조체와 같은 데이터 연결뿐만 아니라, 데이터 및 제어 (함수)를 연결합니다. 따라서 코드는 항상 데이터를 처리하는 전용의 함수를 안전하게 호출 할 수 일련의 기능을 하나의 서브 시스템으로 제공 할 수있는 것입니다.

클래스를 이용하려면 구조체와 마찬가지로 먼저 선언해야합니다. Objective-C 언어의 클래스의 선언은 예약어와 구문이 아닌 컴파일러 지시문 을 이용합니다. 컴파일러 지시문은 컴파일러에 Objective-C에서 확장 된 클래스의 선언과 구현 등에 사용되고, @ 표시로 시작 하는 특징을 가지고 있습니다.

클래스를 선언하는 컴파일러 지시문은 @interface 로 시작 @end 로 끝난다. 이들 사이에 클래스에 관련된 변수 영역과 함수를 선언합니다. Objective-C의 클래스 선언과 정의의 관계는 다른 언어에 비해 복잡하기 때문에 처음에는 당황 할지도 모릅니다.

@interface 클래스 명 : 부모 클래스 명
{
	인스턴스 변수 선언
	...
}
메소드 선언
@end

이 시점에서 C 언어 계의 객체 지향 언어와는 선언 방법이 꽤 다르다는 것을 알 수 있습니다. 인스턴스 변수 는 클래스에 관련된 변수로, 구조체의 멤버에 동일한 존재입니다. 그러나 구조와는 달리 인스턴스 변수에 클래스의 외부에서 액세스 할 수 없습니다. 인스턴스 변수를 이용할 수있는 것은 원칙적으로 클래스에 관련하는 메소드만을라고되어 있습니다. 인스턴스 변수가 존재하지 않는 경우는 인스턴스 변수 선언과 {}를 생략 할 수 있습니다.

메소드 는 클래스에 관련된 함수입니다. 일반 함수와의 차이점은 메서드는 메서드를 호출 한 클래스의 실체와 관련된 있기 때문에 직접 인스턴스 변수에 액세스 할 수 있습니다.

클래스 이름 뒤에 부모 클래스 를 지정하면 있지만 부모 클래스는 무엇입니까? 객체 지향 한 번 정의 된 기능을 확장하는 상속 이라는 기능을 제공해야합니다. 상속 관계는 잘 생물의 진화론에 비유 개나 고양이 등의 다양한 실체에 공통되는 추상적 인 기능을 포유류 클래스로 정의하고 개 클래스와 고양이 클래스는 포유류 클래스를 상속하도록 프로그램 입니다.

부모 클래스를 지정하지 않는 클래스는 다른 클래스의 정점이되기 위해 루트 클래스 라고합니다. Java 또는 .NET에서는 플랫폼이 기본이되는 루와 클래스를 제공하는 구조를 채용하고 C ++ 언어는 루트 클래스를 정하지 않고 루트 클래스를 개발자가 개발할 수 있도록 설계되어 있습니다. Objective-C는 그 중간적인 형태로 원칙적으로는 루트 클래스에서 개발할 수 있지만, 사실상은 컴파일러 등의 처리 계가 루트 클래스를 제공해야합니다.

루트 클래스는 처리 계에 따라 다르지만 GCC이면 Object 클래스가 Mac OS X의 Cocoa 환경이면 NSObject 클래스가 루트 클래스입니다. 독자적인 루트 클래스를 개발하는 경우라면 부모 클래스를 지정하지 않지만 일반적으로 처리 계가 제공하는 루트 클래스를 상속합니다. 루트 클래스를 개발하는 경우에만 선언은 다음과 같이 될 것입니다.

@interface 클래스 이름
{
	인스턴스 변수 선언
	...
}
메소드 선언
@end

왜 루트 클래스를 계승하지 않으면 안되는 것인지라고하면, 루트 클래스는 클래스가 제대로 작동하는 데 필요한 기본적인 기능을 제공하는 역할이 있기 때문입니다. 루트 클래스가 존재하지 않으면, 클래스의 실체를 작성하기위한 번잡 한 수속을 모든 클래스에서 설명해야한다 없게되어 버립니다. 힙 메모리의 확보 나 해방 등의 기본적인 처리 절차는 루트 클래스에 맡겨 버리는 것으로, 개발자는 개발 목적의 기능을 설명하는 데 집중할 수 있습니다.

인스턴스 변수의 선언은 일반 변수와 비슷하지만, 메소드 선언은 함수의 선언과는 상당히 다릅니다. 이 메소드 선언의 사양은 C ++에 비해 Objective-C는 C 언어 프로그래머에게 받아 들여지지 않았다 큰 요인의 하나가 될 것으로 간주됩니다. 메소드 선언은 다음과 같습니다.

- (반환 값형) 메소드 명 : 가인 목록 ...;

왜 함수의 선언과 이정도로도 다른지 C 언어와의 하이브리드 언어로서의 사양상의 문제가 부각되고 있습니다. 첫 마이너스 기호 -는이 메소드가 클래스의 실체 인 오브젝트에 관련하는 것을 나타냅니다. 일반 메소드는 - 기호 좋지만 객체가 아닌 클래스에 관련하는 메소드의 선언이면 + 기호를 지정합니다. - 기호의 메소드를 인스턴스 메소드 라고 + 기호로 시작되는 메소드를 클래스 메소드 라고합니다. 인스턴스 메소드와 클래스 메소드의 차이는 나중에 자세히 설명 하겠지만, 일반적인 메소드는 -에서 시작된다고 생각합니다.

반환 값 형을 봐도 알 수 있듯이 메소드 선언에서는 형태를 ()로 묶습니다. 메소드가 인수를받는 경우는 콜론 :에 이어 가인 목록을 지정합니다. 가인 목록도 일반 변수 선언과 달리 변수 형을 () 안에 지정하고 그 뒤에 변수 이름을 지정합니다.

C 함수의 기본 반환 값은 int 형 이었지만, 메소드의 반환 값의 디폴트는 id 형 이라는 Objective-C에서 추가 된 객체를 나타내는 범용 형으로되어 있습니다. 반환 값형은 생략 할 수 있지만, 일반적으로 생략 할 것이 아니라, 명시 적으로 선언해야 겠지요. 반환 값을 돌려주지 않는 경우는 (void)을 지정합니다.

@interface Test : Object
- (void) method;
@end

이 Test 클래스의 선언은 반환 값을 돌려주지 않고 인수를받지 않는 method 메소드를 선언하는 단순한 클래스를 선언하고 있습니다. 클래스 및 메서드 이름의 명명 규칙 은 C 언어의 변수 나 구조체 이름 지정 규칙과 같은 고유 식별 할 수있는 알파벳으로 시작하는 식별자해야합니다. 그러나 습관으로 클래스 이름은 대문자로 시작하고 메소드 이름은 소문자로 시작합니다.

그런데, 클래스와 메소드를 무사히 선언 할 수 있었지만, 메소드는 메소드의 이름과 형태만을 선언 한 것만으로 처리 코드를 작성하는 정의가 존재하지 않습니다. 실은, Objective-C에서는 클래스의 선언과 정의가 완전히 분리되어 있고, 클래스 선언에서 인스턴스 변수와 메소드의 선언 밖에 할 수 없습니다. 클래스 선언에서 정의로 구체화하려면 @implementation 컴파일러 지시문을 사용하여 클래스를 정의해야합니다.

@implementation 클래스 명
메소드 정의
...
@end

@implementation 컴파일러 지시문은 @ interface로 선언 된 클래스의 구현을 작성합니다. 선언 한 메소드는이 자리에서 정의되어야합니다. 클래스에서 메소드가 선언되어 있지 않은 경우, @ implementation에 기술하는 것은 아무것도 없지만, 그래도 정의되지 않은 클래스는 @implementation에 명시 적으로 구현해야합니다.


클래스의 인스턴스화

클래스 선언 및 정의하면 클래스를 사용할 수있게됩니다 만, 그대로는 사용할 수 없습니다. 클래스를 이용하기 위해 필요한 메모리 공간을 할당 적절한 초기화하고 처음으로 클래스가 제대로 작동하게됩니다. 클래스의 선언 정보를 기반으로 메모리를 할당하는 것을 인스턴스화 라고 부르고, 확보 된 메모리 영역을 인스턴스 라고합니다. 인스턴스라고 부르는 경우 일반적으로 클래스의 정보에 따라 확보 된 실체를 나타냅니다 만, 일반적으로는 오브젝트 라고도합니다.

C ++ 언어 나 Java 언어 등 일반적인 객체 지향 언어이면 new 연산자가 존재하고이 연산자가 클래스의 선언 정보에 따라 인스턴스를 생성하고 초기화 해줍니다. 그러나 놀랍게도 Objective-C 언어는 인스턴스의 생성을 포함하여 클래스를하여야한다고 규정하고 있습니다. 그러나 클래스의 인스턴스 개체에 필요한 크기를 확인하고 메모리를 할당 등 번잡 한 초기화 처리가 필요합니다. 이것을 모든 클래스에서 구현하는 것은 현실적이지 않기 때문에이 작업을 혼자서 맡아주는 것이 루트 클래스의 존재입니다.

Object 클래스는 Object 클래스를 포함한 그것을 계승하는 클래스의 인스턴스를 적절히 생성하는 alloc 클래스 메소드를 정의하고 있습니다. 일반 인스턴스 메서드는 메서드를 호출하기 위해 인스턴스가 필요하지만, 클래스 메소드는 인스턴스가 없어도 실행할 수 있다는 성질이 있습니다. 따라서 alloc 메소드는 인스턴스가 존재하지 않아도 호출에 문제는 없습니다. alloc 메소드는 인스턴스를 생성하기위한 클래스 메소드이므로 자주 팩토리 메소드 라고도합니다.

+ alloc;

이것이, Object 클래스에서 선언되어있는 alloc 메소드입니다. +로 시작하기 때문에,이 메소드는 클래스 메소드 인 것을 어필하고 있습니다. 반환 값형은 생략되어 있기 때문에 기본 id 형식이 반환됩니다.

id 형식 개체를 나타내는 범용 형으로 일종의 void *와 같은 것이라고 생각합니다. 즉, 객체의 클래스 형이 왜있는 모든 객체는 id 형식의 변수에 저장할 수 있습니다.

그런데, 클래스를 생성하는 alloc 메소드를 호출해야하지만, 방법은 어떻게 호출합니까? C ++ 계의 객체 지향 언어를 경험 한 많은 프로그래머는 직관적으로 다음과 같은 코드를 상상하는 것입니다.

id obj = 클래스 이름 .alloc ();

불행히도, Objective-C에서는, 많은 객체 지향형 언어로 채용되고있는이 기술 방법은 잘못된 것입니다. Objective-C에서 클래스 메소드를 호출하려면 다음과 같이 설명해야합니다.

[클래스 명 메소드 명 : 인수리스트 ...]

이것은 Smalltalk 언어를 객체 지향 부분의 어원으로하는 Objective-C의 특징입니다. 인스턴스 메소드를 호출하면 클래스 이름 부분에 개체를 지정해야합니다. C에서 []는 배열의 요소를 지정하는 데 사용되고있었습니다 만, 컴파일러는 [] 전후의 검사에서 메서드 호출인지 배열의 요소 지정인지를 판단 할 수 있습니다 .

이 메서드를 호출하기위한 []를 메시지 식 이라고합니다. Objective-C에서는 객체에서 (함수의 주소 등을 이용해) 메소드를 직접 호출하는 것이 아니라 객체에 메서드와 관련된 메시지를 보내는 것입니다. 메시지 식으로 객체에 메시지가 전송되면 객체는 주어진 메시지에 따라 적절한 방법을 시작하려고하는 것입니다. 이러한 동적 인 구조는 유연성을 확보하지만 C 함수 호출에 비해 오버 헤드는 배 이상 걸린다고 생각합니다. 물론 컴파일러가 최적화 등을 실시하는 경우에는 그러하지는 않지만, 메시지 의한 동적 메서드 호출은 런타임에 메서드를 검색하기 위해 반드시 오버 헤드가 걸립니다.

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

@interface Test : Object
- (void) method;
@end

@implementation Test
- (void) method {
	printf ( "Kitty on your lap \ n");
}
@end

int main () {
	id obj = [Test alloc];
	[obj method];
	
	return 0;
}

그런데, 이것이 간단한 Objective-C에 의한 클래스의 실현입니다. @interface에 의한 클래스의 선언은 루트 클래스 Object를 계승하는 Test 클래스를 선언하고 있습니다. Test 클래스는 반환 값을 돌려주지 않는 인수를받지 않는 method 메소드를 선언합니다. 따라서 @implementation에서이 메소드를 구현해야합니다.

클래스의 선언과 정의가 종료되면 다음 그 클래스를 사용할 수있게됩니다. main () 메소드는 객체를 포함하는 id 형의 변수 obj를 선언하고 동시에 Test 클래스의 인스턴스를 생성하고이를 할당합니다. [Test alloc]는 Test 클래스의 클래스 메소드 alloc를 호출한다는 의미입니다. Test 클래스에서 alloc는 정의하지 않지만, alloc 메소드는 Object 루트 클래스에서 정의되어 있기 때문에 제대로 작동합니다. alloc 메소드는 Test 클래스의 선언 정보에 따라 적절하게 메모리를 할당 생성 된 오브젝트를 돌려줍니다.

Test 클래스는 인스턴스 메소드 method를 정의하고 있기 때문에 생성 된 객체의 method 메소드를 메시지 식으로 시작할 수 있습니다. 프로그램은 인스턴스 생성 직후에 [obj method]라는 메시지 표현식을 작성하여 Test 클래스의 method 메소드를 시작합니다. 그 결과, 화면에는 Kitty on your lap라는 문자열이 나타나는 것입니다.

덧붙여서 개체를 처분 해 버리는 경우 인스턴스의 생성과 method 메소드의 호출은 다음과 같이 설명 할 수 있습니다.

[Test alloc] method]

이 경우 내부 [Test alloc]가 먼저 실행되고, 생성 된 인스턴스를 참조하는 id 형의 객체가 반환됩니다. 그리고 반환 된 id 형식의 객체에 두 method 메시지를 전송하여 메소드를 호출하는 것입니다. 이와 같이, 메시지 식은 중첩 할 수 있습니다. 이것은 (Test. alloc ()). method ()라고하는 함수의 호출 관계에 비유 할 수있을 것입니다.

위의 프로그램과 같이 클래스의 선언과 정의의 장소는 자유롭 습니다만, 습관으로 클래스의 선언은 헤더 파일에 정의는 클래스 명과 같은 이름의 * .m 파일에 기술합니다.