2010년 2월 8일 월요일

4. 메소드

4. 메소드


억세서 메소드
클래스의 선언과 정의를 바르게 하고, Object 루트클래스의 alloc 메소드를 호출하면 클래스의 인스턴스가 생성됩니다. 클래스의 정의는 구조체의 선언과 같은 것으로, 인스턴스를 생성하는 것은 구조체형의 변수를 정의하고 구조체를 표현하기 위하여 필요한 메모리를 할당하는 행위와 비슷합니다. 그러나 클래스는 멤버변수와 그것을 처리하는 전용함수를 연결하는 점에서 구조체와 크게 다릅니다.


전회에 클래스를 선언하고, 메소드를 정의하여 그것을 호출하는 일을 했습니다. 전회의 메소드는 인수나 반환값을 전달하지 않는 매우 단순한 것이었지만, 여기서는 보다 복잣한 메소드를 실현하기 위하여 메소드를 상세히 해설합니다. 특히, 메소드는 함수와는 달리, 설계론의 개론에서 인스턴스나 클래스의 역할에 관련되어야 합니다.


예를 들면, 2차원좌표의 점을 나타내는 Point 클래스를 작성한다고 합니다. 이 경우 Point 클래스는 좌표 X와 Y를 제공해야 합니다. Point 클래스는 int형의 인스턴스변수 x와 y를 선언하고, 이들의 값을 제어하는 메소드군을 제공해야 할 필요가 있습니다.


원칙적으로, 클래스의 인스탄스변수에는 클래스의 외부에서는 억세스할 수 없습니다. 왜냐하면, 변수가 자유롭게 변경되어 버리면 변수의 의미나 입출력하는 데이터의 사양이 변경되는 경우 등, 보수성이나 코드전체의 유연성이 저하되기 때문입니다. 그래서, Objective-C 에는 변수에 억세스하기 위하여 메소드를 사용합니다. Point 클래스의 기본적인 선언은 다음과 같이 될 것입니다.

 

@interface Point : Object
{
 int x, y;
}
- (void)setPoint:(int)ptx:(int)pty;
- (int)getX;
- (int)getY;
@end

 

이 클래스의 선언에는 좌표를 보존하기 위하여 변수 x와 y를 선언하고, 이 변수에 클래스 외부에서 접근하기 위한 메소드를 선언합니다. setPoint 메소드는 x와 y의 값을 변경하기 위한 메소드로 getX와 getY메소드는 각각의 변수를 가져오기 위한 메소드입니다. 이같은 메소드를 특별히 억세서메소드라고 부릅니다. 또, 이같은 인스턴스의 성질에 관련된 외붕에 제공하기 위한 정보를 특별히 프로퍼티라고도 합니다.

 

인수를 받아들이는 메소드는 인수형을 ()의 속에 지정하고, 그 다음에 가인수의 이름을 지정합니다. 이 때의 ()는 캐스트식과 같이 형을 지정하지 않는 경우에는 반환값과 같이 id형이 기본값이 됩니다. 복수의 인수가 있는 경우, 다시금 콜론 : 에 이어 지정합니다. 보다 구체적으로는 메소드의 선언은 다음과 같습니다.

 

- (반환형)메소드명: (인수형) 변수명 레이블: ...

 

복수의 인수를 받아들이는 메소드는 변수명의 뒤에 레이블을 지정할 수 있습니다. 비교적, Objective-C의 세계에는 레이블을 지정하는 일이 습관이 되어있습니다만, 이 레이블과 콜론은 메소드명의 일부라고 인식되어지는 것입니다.


레이블과 콜론이 이름의 일부라고 인식되어지기 때문에, Objective-C에는 같은 반환값, 인수, 메소드명을 가진 메소드를 구별하여 호출하는 일을 할수 있습니다. 예를 들어 (void)setPoint:(int):(int) 라고 하는 메소드와 (void)setPoint:(int) label:(int) 메소드는 다른 메소드로 선언, 정의할 수 있습니다.

 

인수가 붙은 메소드의 호출에는 메시지식에 메소드명에 이어서 인수에 넘겨주는 값을 지정합니다. 레이블을 지정하지 않은 전자의 setPoint 의 경우 [obj setPoint:x:y] 라고 하는 형으로 호출하는대 반하여, 레이블을 붙인 메소드는 [obj setPoint:x label:y] 라는 형태로 호출합니다. 인수의 수나 레이블이 다르면, 메소드명이 같아도 구별하여 호출할수 있는 구조입니다. 특정의 기능을 제공하는 메소드를 여러 가지 형에 대응하여 제공하고 싶은 경우에 레이블이 필요하게 됩니다. setPoint 메소드를 , int형 이외의 정수에도 대응시키고 싶은 경우등은 중요할 것입니다.

 

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

@interface Point : Object
{
 int x, y;
}
- (void)setPoint:(int)ptx int:(int)pty;
- (int)getX;
- (int)getY;
@end

@implementation Point
- (void)setPoint:(int)ptx int:(int)pty {
 x = ptx;
 y = pty;
}
- (int)getX {
 return x;
}
- (int)getY {
 return y;
}
@end

int main() {
 id point1 , point2;
 point1 = [Point alloc];
 point2 = [Point alloc];

 [point1 setPoint:16 int:32];
 [point2 setPoint:256 int:128];

 printf("point1:X=%d, Y=%d\n", [point1 getX] , [point1 getY]);
 printf("point2:X=%d, Y=%d\n", [point2 getX] , [point2 getY]);
 return 0;
}

 

이 프로그램의 Point 클래스는 2개의 정수형인수를 받아들이는 setPoint:int: 메소드와 설정되어있는 좌표를 반환하는 getX, getY메소드를 선언하고 있습니다. setPoint 메소드의 선언은 setPoint(int)ptx:(int)pty 에도 문제없습니다만, 장래 setPoint를 확장하는 일을 생각할 경우는, 레이블을 지정하는 것이 좋을 것입니다.

 

main() 메소드에는 alloc 메소드를 이용하여 Ppint 클래스의 인스턴스를 2개 만듭니다. point1 변수와 point2변수가 가리키는 인스턴스는 다르기 때문에, 각각의 인스턴스에 설정된 값은 개별의 메모리에 보존되어있는 것이고, 출력결과에서 확인할 수 있습니다.

 


암묵의 self
메소드의 스코프범위 내에는 가인수나 선언된 변수이외에 암묵의 변수인 self과 정의되어있습니다. self 변수는 id형에 항상 메소드를 호출하는 인스턴스를 참조합니다. 즉, 메소드를 실행하는 오브젝트자신을 나타내는 변수가 self입니다.


self 는 메소드이에의 장소에서든 사용할 수 없고, 항상 메소드 실행코드부분에만 암묵적으로 존재합니다. self를 이용함에 다라, 오브젝트의 인스턴스변수에 오브젝트에서 참조하는 일이 가능합니다. 이것은, 메소드의 가인수의 변수명이 인스턴스 변수명을 은폐하고 있을 때등에 이용할 수 있습니다. 억세서메소드에는 특히 중요한 존재일 것입니다.

 

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

@interface Point : Object
{
 int x, y;
}
- (void)setPoint:(int)ptx int:(int)pty;
- (int)getX;
- (int)getY;
@end

@implementation Point
- (void)setPoint:(int)x int:(int)y {
 self->x = x;
 self->y = y;
}
- (int)getX {
 return x;
}
- (int)getY {
 return y;
}
@end

int main() {
 id point1 , point2;
 point1 = [Point alloc];
 point2 = [Point alloc];

 [point1 setPoint:32 int:64];
 [point2 setPoint:256 int:128];

 printf("point1:X=%d, Y=%d\n", [point1 getX] , [point1 getY]);
 printf("point2:X=%d, Y=%d\n", [point2 getX] , [point2 getY]);
 return 0;
}

 

이 프로그램의 setPoint:int: 메소드는 가인수에 선언된 이름이 인스턴스변수 x와 y에 충돌하고 잇습니다. 이것자체는 문제가 없습니다만, 이 변수의 스코프범위에는 인스턴스변수가 은폐되어 버립니다. 그래서 인스턴스변수에 억세스하는 수단으로, 현재의 메소드를 실행하고 있는 오브젝트를 참조하는 self변수를 사용합니다. 클래스외부에서 인스턴스변수에 참조하는 일은 할수 없지만, 메소드는 클래스의 내부이므로, 오브젝트에서 직접 인스터스변수에 억세스할 수 있습니다. 프로그램에는 self->x 라는 형태로, 인스턴스 변수에 넘겨준 데이터를 보존하고 있습니다.

또, 메소드에서 같은 인스탄스의 다른 메소드를 호출하는 경우에도 self가 필요합니다. 일부 메소드가 기능의 일부를 공유하고 있는 설계등에는 동일한 클래스의 다른 메소드를 호출할 필요가 있습니다.

 

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

@interface Test : Object
- (void)methodA;
- (void)methodB;
@end

@implementation Test
- (void)methodA {
 printf("method A\n");
 [self methodB];
}
- (void)methodB {
 printf("method B\n");
}
@end

int main() {
 [[Test alloc] methodA];
 return 0;
}

 

이 프로그램의 Test클래스에는 methodA메소드에서 methodB메소드를 self 오브젝트를 사용하여 호출하고 있습니다. self는 methodA를 실행하고 있는 인스턴스이므로, 동일 인스턴스의 methodB를 호출한다는 것입니다.

 

 

원본 : http://wisdom.sakura.ne.jp/programming/objc/objc4.html

댓글 없음:

댓글 쓰기