<출처 : http://wwwww.kr/?mid=objectivec&page=2&document_srl=31076 >
selector
- 프로그램 내부에서 메서드를 호출하면 컴파일 시 내부에 표현되는 값으로 변경을 가해서 호출합니다.
- 메서드의 내부 표현에 해당하는 데이터 타입을 SEL 타입이라고 합니다.
- SEL타입에 데이터를 대입하는 경우에는 @ selector(메서드명)으로 메서드명을 넘겨주면 됩니다.
SEL 변수명 = @selector(메서드명);
- 매개 변수가 있는 경우에는 메서드 명 뒤에 :을 붙여서 사용합니다
- @selector를 호출할 때는 객체가 performSelector:@selector(메서드)의 형태나 SEL 변수를 이용합니다.
- 매개변수는 객체만 가능하며 다음과 같이 호출합니다.
performSelector:@selector(메서드:) withObject:객체
- 이를 적절히 이용하면 동적으로 메시지를 변경할 수 있습니다.
- (SEL)변수 ------> @selector(메서드명)
- 없는 메서드를 호출하거나 매개변수를 안만든 경우 unrecognized selector 오류 발생
01.
#import <Foundation/Foundation.h>
02.
@interface Test : NSObject
03.
-(
void
)Disp;
04.
@end
05.
@implementation Test
06.
-(
void
)Disp
07.
{
08.
NSLog(@
"Disp 입니다"
);
09.
}
10.
@end
11.
int
main()
12.
{
13.
Test *Obj = [Test
new
];
14.
[Obj performSelector:@selector(Disp)];
15.
[Obj Disp];
16.
return
0;
17.
}
결과
2010-11-15 09:37:29.307 Test[409:a0f] Disp 입니다
2010-11-15 09:37:29.309 Test[409:a0f] Disp 입니다
01.
#import <Foundation/Foundation.h>
02.
@interface Test : NSObject
03.
-(
void
)Disp;
04.
-(
void
)Print;
05.
@end
06.
@implementation Test
07.
-(
void
)Disp
08.
{ NSLog(@
"Disp 입니다"
);}
09.
-(
void
)Print
10.
{ NSLog(@
"Print 입니다"
);}
11.
@end
12.
int
main()
13.
{
14.
Test *Obj = [Test
new
];
15.
int
sel;
16.
NSLog(@
"숫자를 입력하세요 1:Disp 2:Print"
);
17.
scanf
(
"%d"
, &sel);
18.
SEL dele;
19.
if
(sel == 1)
20.
dele = @selector(Disp);
21.
else
22.
dele = @selector(Print);
23.
[Obj performSelector:dele];
24.
return
0;
25.
}
결과
2010-11-15 09:39:35.597 Test[465:a0f] 숫자를 입력하세요 1:Disp 2:Print
1
2010-11-15 09:39:28.732 Test[454:a0f] Disp 입니다
2
2010-11-15 09:39:36.940 Test[465:a0f] Print 입니다
매개 변수가 있는 selector
- 매개 변수가 있는 경우에는 @selector(메서드:) 형태로 정의하고 호출할 때는
performSelector:@selector(메서드:) withObject:object
형태로 호출합니다.
- 2개의 매개변수를 사용하면 performSelector:@selector(메서드:) withObject:object withObject: object 형태 로 호출합니다.
01.
#import <Foundation/Foundation.h>
02.
@interface Test : NSObject
03.
{
04.
int
n;
05.
}
06.
-(id)init:(
int
) a;
07.
-(
void
)Disp:(Test *)Temp;
//프로토타입이 완전히 똑같아야 함
08.
-(
void
)Print:(Test *)Temp;
09.
@property
int
n;
10.
@end
11.
@implementation Test
12.
@synthesize n;
13.
-(id)init:(
int
) a
14.
{
15.
self = [super init];
16.
if
(self != nil)
17.
n = a;
18.
return
self;
19.
}
20.
-(
void
)Disp:(Test *)Temp
21.
{
22.
NSLog(@
"%d"
, ++(Temp.n));
23.
}
24.
-(
void
)Print:(Test *)Temp
25.
{
26.
NSLog(@
"%d"
, --(Temp.n));
27.
}
28.
@end
29.
int
main()
30.
{
31.
Test *Obj = [[Test alloc]init:5];
32.
int
sel;
33.
NSLog(@
"숫자를 입력하세요 1:Disp 2:Print"
);
34.
scanf
(
"%d"
, &sel);
35.
SEL dele;
36.
if
(sel == 1)
37.
dele = @selector(Disp:);
38.
else
39.
dele = @selector(Print:);
40.
[Obj performSelector:dele withObject:Obj];
41.
return
0;
42.
}
결과
2010-11-15 09:43:29.039 Test[539:a0f] 숫자를 입력하세요 1:Disp 2:Print
카테고리
- 클래스의 일부 메서드를 구현한 모듈을 Category라고 합니다.
- 사용자 정의 클래스나 Framework가 제공하는 클래스의 기능을 확장하고자 하는 경우 사용하는 기능입니다.
- 기존 클래스의 정의를 변경하지 않은 상태에서 추가하고자 하는 메서드만 추가해서 사용할 수 있습니다.
- 이를 적절히 이용하면 클래스의 분할 구현도 가능합니다.
cf.
NSNumber : 클래스 클러스터
NSNumber *num1 = [NSNumber numberWithInt:100]; //정수
NSNumber *num2 = [NSNumber numberWithFloat:100]; //실수
카테고리의 생성
클래스의 선언과 정의와 유사하며 단 기존 클래스 이름을 사용해야 하므로 기존 클래스의 헤더파일이 import 되어야 합니다.
1.
@interface 클래스명(카테고리명)
2.
메서드의 선언;
3.
@end
4.
5.
카테고리의 구현
6.
@implementation 클래스명(카테고리명)
7.
메서드의 정의;
8.
@end
카테고리 규칙
- 카테고리 이름에는 제한이 없지만 카테고리가 속한 클래스 안에서 카테고리 명과 같은 이름을 사용하는 것은 안됩니다.
- 인스턴스 변수의 선언은 금지됩니다. => 이 경우는 상속을 받아서 처리
- 메서드 선언에는 제한이 없습니다.
- 오버라이딩 하는 것은 바람직하지 않습니다. => 기존 메서드를 호출할 수 없습니다.
- 지역 메서드나 C언어의 함수를 사용하는 것이 모두 가능합니다.
- 파일 명은 일반적으로 클래스명 + 카테고리 명으로 하는 것이 일반적입니다.
프레임워크 클래스의 확장
- 카테고리를 사용하는 것은 사용자 정의 클래스에만 해당되는 것은 아닙니다.
- Framework가 제공해주는 클래스에 대해서도 가능합니다.-
- NSString에는 단위를 붙여서 리턴해주는 메서드가 제공되지 않습니다.
- 사용자는 매번 메서드를 정의해서 사용해야 합니다.
- 이러한 경우 사용자가 이러한 메서드를 확장해서 사용할 수 있으면 매우 편리할 것입니다.
- 이 때 카테고리를 이용하면 매우 유용하게 사용될 것입니다.
- 기존 메서드를 재정의하게 되면 이전 메서드는 가려집니다.
예제
01.
//Unit.h(c header file 추가) - add에서 c/c++파일 메뉴에서 헤더파일 추가
02.
#import <Foundation/NSString.h>
03.
@interface NSString(Unit)
04.
- (NSString *)stringWithAmerica;
05.
- (NSString *)stringWithKorea;
06.
@end
07.
@implementation NSString(Unit)
08.
//문자열의 앞에 $를 붙여서 리턴하는 메서드
09.
- (NSString *)stringWithAmerica;
10.
{
11.
return
[NSString stringWithFormat:@
"$%@"
, self];
12.
}
13.
//문자열의 앞에 \를 붙여서 리턴하는 메서드
14.
- (NSString *)stringWithKorea;
15.
{
16.
return
[NSString stringWithFormat:@
"\\%@"
, self];
17.
}
18.
@end
01.
Main. m파일
02.
#import "Unit.h"
03.
int
main(
int
argc,
char
*argv[])
04.
{
05.
NSAutoreleasePool *pool = [NSAutoreleasePool
new
];
06.
NSString *string = @
"1000"
;
07.
NSLog(@
"America:%@"
, [string stringWithAmerica]);
08.
NSLog(@
"Korea:%@"
, [string stringWithKorea]);
09.
[pool drain];
10.
return
0;
11.
}
결과
2010-11-15 10:00:25.111 Test[715:a0f] America:$1000
2010-11-15 10:00:25.116 Test[715:a0f] Korea:\1000
Protocol
- Object의 역할이나 동작을 표현하는 메서드의 집합
- Java의 Interface가 Objective-C의 프로토콜을 도입한 개념입니다.
- 여러 개의 클래스 또는 오브젝트가 공통적인 동작을 가지고 있을 때 이를 프로토콜에 정의해 두고 이를 상속받아서 자신의 특성에 맞게 구현 한 후 사용합니다.
- 이렇게 프로토콜로부터 상속받아서 이를 전부 구현 하게 된 경우를 프로토콜을 Conform(준수) 했다고 합니다.
- 프로토콜의 선언
1.
@protocol 프로토콜이름
2.
메서드 선언;
3.
@end
- 일반적으로 프로토콜의 이름은 첫 글자가 대문자로 시작합니다.
위처럼 선언한 후 .h 파일에 저장하는 것이 일반적입니다.
프로토콜의 적용
- 프로토콜을 적용할 때는 아래와 같은 방법을 이용하게 됩니다.
1.
@interface 클래스이름: 슈퍼클래스이름 <프로토콜이름>
2.
{ 변수 선언; }
3.
메서드 선언
4.
@end
- 위처럼 작성하면 프로토콜에 선언된 모든 메서드가 선언된 것과 같은 효과를 나타내게 됩니다.
이 때 주의할 점은 프로토콜에 선언된 모든 메서드를 구현해야 하며 여러 개의 프로토콜을 적용하고자 하는 경우 < > 안에서 ,로 구분하여 나열하면 됩니다.
- 프로토콜에 선언된 모든 메서드를 구현하지 않으면 Warning을 나타내게 될 것입니다.
- 카테고리의 선언에도 사용할 수 있으며 이 경우에는 카테고리 이름 다음에 프로토콜을 적용하는 문장을 기재하면 됩니다.
예제
01.
#import <Foundation/NSString.h>
02.
//프로토콜의 생성
03.
@protocol ProtocolToString
04.
- (id) ToString;
05.
@end
06.
@interface Test : NSObject <ProtocolToString>
07.
{
08.
NSString *name;
09.
}
10.
- (id) init;
11.
@end
12.
@implementation Test
13.
- (id) init
14.
{
15.
name = [NSString stringWithFormat:@
"파일명:%s 클래스명:%@"
,__FILE__,self];
16.
return
self;
17.
}
18.
- (id) ToString {
return
(id) name; }
19.
@end
20.
21.
int
main()
22.
{
23.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
24.
id obj = [Test
new
];
25.
NSLog(@
"obj = %@\n"
, [obj ToString]);
26.
[pool drain];
27.
return
0;
28.
}
01.
#import <Foundation/NSString.h>
02.
@protocol ProtocolToString
03.
- (id) ToString;
04.
@end
05.
@protocol ProtocolToAddress
06.
- (id) ToAddress;
07.
@end
08.
@interface Test : NSObject <ProtocolToString,ProtocolToAddress >
09.
{
10.
NSString *name;
11.
NSString *address;
12.
}
13.
- (id) init;
14.
@end
15.
@implementation Test
16.
- (id) init
17.
{
18.
name = [NSString stringWithFormat:@
"파일명:%s 클래스명:%@"
,__FILE__,self];
19.
address = [NSString stringWithFormat:@
"주소:%d 번지"
,self];
20.
return
self;
21.
}
22.
- (id) ToString {
return
(id)name; }
23.
- (id) ToAddress {
return
(id)address; }
24.
@end
25.
int
main()
26.
{
27.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
28.
id obj = [Test
new
];
29.
NSLog(@
"obj = %@\n"
, [obj ToString]);
30.
NSLog(@
"obj의 주소 = %@\n"
, [obj ToAddress]);
31.
[pool drain];
32.
return
0;
33.
}
인스턴스의 제약 _매개 변수의 제약
인스턴스 변수를 선언할 때 Objective-C는 id 타입으로 선언하게 되면 아무런 제약없이 모든 클래스의 인스턴스를 생성할 수 있습니다.
이런 경우 생성되는 인스턴스에 제약을 가하고자 하는 경우에도 프로토콜을 사용해서 제약을 가할 수 있습니다.
이 때는 동적으로 타입을 확인하지 않고 정적으로 타입을 점검하게 됩니다.
인스턴스 변수의 제약
id <프로토콜이름> 인스턴스변수명;
매개 변수의 제약
-(결과형)메서드명:(id <프로토콜이름>)매개변수명;
01.
#import <Foundation/NSString.h>
02.
@protocol ProtocolToString
03.
- (id) ToString;
04.
@end
05.
@interface Test : NSObject <ProtocolToString>
06.
{ NSString *name; }
07.
- (id) init;
08.
@end
09.
@implementation Test
10.
- (id) init
11.
{
12.
name = [NSString stringWithFormat:@
"파일명:%s 클래스명:%@"
,__FILE__,self];
13.
return
self;
14.
}
15.
- (id) ToString {
return
(id)name; }
16.
@end
17.
int
main()
18.
{
19.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
20.
Test <ProtocolToString> * obj = [Test
new
];
21.
NSLog(@
"obj = %@\n"
, [obj ToString]);
22.
[pool drain];
23.
return
0;
24.
}
프로토콜의 선택과 필수의 구분
프로토콜에 선언되는 메서드 앞에 @optional 을 기재하면 메서드를 구현해도 되고 하지 않아도 됩니다.
@required를 기재하면 반드시 반드시 구현해야 합니다.
01.
#import <Foundation/NSString.h>
02.
@protocol ProtocolToString
03.
- (id) ToString;
04.
@optional
05.
- (id) ToAddress;
06.
@end
07.
@interface Test : NSObject <ProtocolToString>
08.
{
09.
NSString *name;
10.
}
11.
- (id) init;
12.
@end
13.
@implementation Test
14.
- (id) init
15.
{
16.
name = [NSString stringWithFormat:@
"파일명:%s 클래스명:%@"
,__FILE__,self];
17.
return
self;
18.
}
19.
- (id) ToString {
return
(id)name; }
20.
@end
21.
int
main() {
22.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
23.
id obj = [Test
new
];
24.
NSLog(@
"obj = %@\n"
, [obj ToString]);
25.
[pool drain];
26.
return
0;
27.
}
'iOS' 카테고리의 다른 글
KeyChain 사용하기. (2) | 2014.11.18 |
---|---|
Delegate, Data Source의 이해 (0) | 2012.04.04 |
Chap6-2. 열거자, enumerator, 고속열거, 다차원배열, set클래스, NSSet, NSCountedSet, Dictionary, NSDictionary, NSMutableDictionary (0) | 2012.03.27 |
Chap6-1. 열거자, enumerator, 고속열거, 다차원배열, set클래스, NSSet, NSCountedSet, Dictionary, NSDictionary, NSMutableDictionary (0) | 2012.03.27 |
다국어 지원을 위한 Custom localization system (0) | 2012.03.26 |