이니셜 라이저


객체의 초기화

인스턴스 변수를 보유하고있는 클래스의 경우 그 대부분이 초기 값을 필요로 할 것이다. 초기화를 잊어 버린 경우 제대로 작동하지 않을 수 있습니다.

일반적인 객체 지향 언어는 객체를 안전하고 확실하게 초기화하는 방법으로 생성자를 제공하고 있습니다. 생성자는 클래스의 인스턴스가 생성 된 직후에 자동으로 호출되는 특수 메서드입니다 만, Objective-C에서는 constructor은 존재하지 않습니다.

대신 생성자는 루트 클래스가 사양에 따라 제공하는 구조를 채용하고 있기 때문에 루트 클래스의 초기화 용 메소드를 명시 적으로 호출해야합니다. Object 루트 클래스와 Mac OS X의 NSObject 클래스에서 init라는 메서드가 개체의 초기화 용 메소드로 정의되어 있습니다. 이 init 메소드에 대해 이니셜 라이저 라고 부릅니다.

- (id) init;

일반적으로 개체를 인스턴스화하는 경우 직후 init 메시지를 전송해야합니다. 이 작업은 자동 것이 아니라 명시 적으로 메시지에서 호출해야합니다. 일반적으로 다음과 같이 기술되어 있습니다.

[클래스 이름 alloc] init]

하지만 new 메소드를 사용하면 위의 문장을 내부에서 실행주기 때문에 이니셜 라이저가 자동으로 호출되는 구조를 재현 할 수 있습니다. C ++ 계의 혈통의 객체 지향 언어의 경험자라면 이쪽이 익숙해 질지도 모릅니다.

+ (id) new;

어느 쪽을 사용 할까는 개발자의 취향 이지요. 가령, 이니셜 라이저가 특히 초기화 할 내용이나 처리 코드가없는 클래스에 대해서도 향후 확장 등에 대응하기 위해 통일 한 취급 방법을해야합니다.

Object 루트 클래스를 상속받은 새로운 클래스를 선언했을 경우, init 메소드를 오버라이드 (override)하는 것으로 초기화 처리를 추가 할 수 있습니다. 인스턴스 변수 등의 초기 값과 시스템에 대한 등록 문의 처리, 클래스가 동작하기 위해 필요한 사전 데이터의 읽기 등은이 자리에서하면 좋을 것입니다. 그러나 init 메소드를 재정의하는 경우 Object 클래스의 init 메소드를 호출하는 것을 잊지 마십시오.

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

@interface Point : Object
{
	int x, y;
}
- (id) init;
- (int) getX;
- (int) getY;
@end

@implementation Point
- (id) init {
	[super init];

	x = y = 0;
	printf ( "init method \ n");
	return self;
}
- (int) getX {return x;}
- (int) getY {return y;}
@end

int main () {
	id pt = [Point new];
	printf ( "X = % d, Y = % d \ n", [pt getX, pt getY]);

	return 0;
}

이 프로그램은 좌표를 나타내는 X와 Y 값을 제공하는 Point 클래스를 실현하고 있습니다. Point 클래스는 Object 루트 클래스를 상속하고 init 메서드를 재정의합니다. 따라서 new 메소드를 사용하여 인스턴스를 생성하면 인스턴스 생성 후에 init 메소드가 불려갑니다.

이 프로그램의 init 메소드에서는 먼저 부모 클래스를 적절히 초기화 할 필요가 있기 때문에 super에 init 메시지를 보낼 수 있습니다. 부모 클래스의 init 메소드가 실행되면,이 시점에서 부모 클래스의 모든 기능이 안전하게 이용할 수있는 것이 보장됩니다. 다음 인스턴스 변수 x와 y를 0으로 초기화하고 이니셜 라이저가 호출되었는지를 시각적으로 확인하기 위해 printf () 함수로 표준 출력에 문자열을 출력합니다.


지정 이니 샤

init 메소드는 인스턴스가 생성 된 직후에 초기화를 위해 호출되는 통일적인 초기화 메서드입니다 만, 인수를받을 수 없습니다. 서브 클래스가, 서브 클래스에서 새로 추가 된 변수를 초기화하는 값을 인수로부터 얻을 수 있다면 편리합니다. 따라서, 서브 클래스에서 새로운 이니셜 라이저를 선언해야합니다. 이 같은 Object 루트 클래스의 init 메소드와는 다른 이니셜 라이저를 지정 이니셜 라이저 라고 부릅니다.

지정 이니셜 라이저는 습관적으로 initWith에서 시작하는 인수를받는 메소드입니다. 서브 클래스에서 슈퍼 클래스의 지정 이니셜 라이저를 재정의하는 경우 반드시 슈퍼 클래스의 지정 이니셜 라이저를 호출 할 필요가 있습니다. 그렇지는 습관적인 설계의 문제가 될 것입니다.

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

@interface Point : Object
{
	int x, y;
}
- (id) init;
- (id) initWithPoint : (int) x int : (int) y;
- (int) getX;
- (int) getY;
@end

@implementation Point
- (id) init {
	[super init];
	return [self initWithPoint : 0 int : 0];
}
- (id) initWithPoint : (int) x int : (int) y {
	self-> x = x;
	self-> y = y;
	return self;
}

- (int) getX {return x;}
- (int) getY {return y;}
@end

int main () {
	id pt1 = [Point new];
	id pt2 = [[Point alloc] initWithPoint : 400 int : 300];

	printf ( "pt1.X = % d, pt1.Y = % d \ n", pt1 getX, pt1 getY]);
	printf ( "pt2.X = % d, pt2.Y = % d \ n", pt2 getX, pt2 getY]);

	return 0;
}

이 프로그램의 Point 클래스에서는 지정된 이니셜 라이저 initWithPoint 메소드를 정의하고 있습니다. initWithPoint는 자동으로 호출되는 메소드는 아니기 때문에, 명시 적으로 호출해야합니다. 일반적으로 init 메소드 나 지정 이니셜 라이저는 가장 인수를 많이받을 이니셜 라이저를 순서대로 호출하는 형태가 가장 안정적인 설계가 될 것입니다.