이 항목은 작성 중입니다.
이 항목은 작성 중인 항목입니다. 내용이 불완전할 수 있습니다. 충돌의 위험이 있으니 history를 확인한 후 작성하는 것을 권장합니다. 이 문서가 오랫동안 편집되지 않았다면 이 틀을 제거해 주세요.
@interface 명령과 @end 명령이다.@interface 명령은 선언하는 클래스의 이름과 상속하는 부모 클래스 이름, 그리고 쉼표로 구분된 준수할 프로토콜 이름의 목록을 인자로 받는다. 형식은 다음과 같다:@interface 클래스 이름 : 부모 클래스 이름 <준수할 프로토콜 이름 목록>여기서 부모 클래스 이름과 준수할 프로토콜 이름 목록은 선택적이다. 즉, 어떠한 클래스도 상속하지 않아 그 자신이 최상위 뿌리(root) 클래스가 될 수도 있고 어떠한 프로토콜도 준수하지 않을 수 있다.
@end 명령은 @interface 명령의 영역을 닫는다.// 뿌리 클래스 @interface ParentClass1 @end // 뿌리 클래스를 상속한 클래스 @interface ChildClass1: ParentClass1 @end // 또 다른 뿌리 클래스이면서 동시에 Protocol1을 준수 @interface ParentClass2 <Protocol1> @end // 또 다른 뿌리 클래스를 상속하면서 동시에 (상속받은) Protocol1과 Protocol2, Protocol3를 준수 @interface ChildClass2: ParentClass2 <Protocol2, Protocol3> @end
// 클래스 메서드 선언문 + (반환형) 메서드_이름 ; // 인스턴스 메서드 선언문 - (반환형) 메서드_이름 ;선언문에서
(반환형) 부분은 생략 가능하다. 생략하면 기본 반환형인 id가 사용된다.// 알림: 읽기 쉽도록 메서드 이름에 언더스코어(_)를 포함시켰다. // 즉, 여기서 메서드 이름의 언더스코어는 필수요소가 아닌, 메서드 이름의 일부이다. // 인자를 받지 않는 경우. 메서드_이름 // 인자를 하나 받는 경우. // 이 경우, 메서드 이름은 '메서드_이름과_인자:'가 된다. 메서드_이름과_인자:(인자형)인자_이름 // 인자를 두 개 받는 경우. // 이 경우, 메서드 이름은 '메서드_이름과_인자1:인자2:'가 된다. 메서드_이름과_인자1:(인자형)인자_이름1 인자2:(인자형)인자_이름2 // 인자를 세 개 받는 경우. // 이 경우, 메서드 이름은 '메서드_이름과_인자1:인자2:인자3:'이 된다. 메서드_이름과_인자1:(인자형)인자_이름1 인자2:(인자형)인자_이름2 인자3:(인자형)인자_이름3 // 이 정도면 이해했겠지.
// 클래스 메서드. 반환형은 char *. // 메서드 이름은 'iTakeNoParameter'. +(char *)iTakeNoParameter; // 클래스 메서드. 반환형은 id. // 메서드 이름은 'allocWithZone:'. // 하나의 인자를 받으며, 그 형은 NSZone *, 이름은 aZone. +allocWithZone:(NSZone *)aZone; +(id)allocWithZone:(NSZone *)aZone; // 같은 표현 // 인스턴스 메서드. 반환형은 NSInteger. // 메서드 이름은 'numberOfCharacter:inString:'. // 인자는 두 개를 받는다. 첫번째는 unichar형의 ch, 두번째는 NSString *형의 str. -(NSInteger)numberOfCharacter:(unichar)ch inString:(NSString *)str; // 인스턴스 메서드. 반환형은 없음. // 메서드 이름은 'drawRectangleOfWidth:height:upperLeftX:upperLeftY:'. // 인자는 네 개를 받는다. 모든 인자는 CGFloat형이고 그 이름은 각각 w, h, x, y이다. -(void)drawRectangleOfWidth:(CGFloat)w height:(CGFloat)h upperLeftX:(CGFloat)x upperLeftY:(CGFloat)y;콜론 역시 메서드 이름의 일부임을 유의하자.
@interface 명령 바로 다음이다:
@interface ExampleClass: ExampleSuperClass <ExampleProtocol>
{ // 인스턴스 변수 선언 시작
int exampleInteger; // struct를 만들 때처럼 변수를 선언해주면 된다.
char exampleCharacter;
NSString *exampleString;
// 기타 인스턴스 변수를 선언한다.
} // 인스턴스 변수 선언 끝
// 메서드 선언부
@end
@private, @protected, @public 명령을 사용해서 인스턴스 변수의 가시성을 조절할 수 있다:
@interface ExampleClass: ExampleSuperClass <ExampleProtocol> {
double iAmProtectedByDefault; // 기본 가시성은 @protected이다.
@private
int privateInteger; // @private 변수는 이 클래스 소속의 메서드에서만 접근 가능하다.
char privateCharacter;
@protected // 이렇게 다른 가시성 명령을 만나기 전까지는 이전 가시성 명령이 계속 적용된다.
int protectedInteger; // @protected 변수는 이 클래스와 상속받은 하위 클래스 소속의 메서드에서만 접근 가능하다.
char protectedCharacter;
@public
int publicInteger; // @public 변수는 개나 소나 다 접근 가능하다.
char publicCharacter;
@private
int privateInteger2;
@public
char publicCharacter2;
@protected
float protectedFloat;
int iAmProtectedToo;
}
// 메서드 선언부
@end
가시성 명령은 어디까지나 선택적이다. 명시적인 가시성 명령이 없으면 인스턴스 변수에는 기본적으로 @protected가 적용된다.@interface 내부에 인스턴스 변수 선언을 넣는 것에 반대하는 입장이다. 따라서 이렇게 할 수도 있다는 것만 알고 다음으로 넘어가도록 하자. 다른 방법은 클래스 정의 부분에서 알아볼 것이다.@public으로 놓는 미친 짓을 하는 게 아니라면 접근자와 변경자를 써야 한다.-(int)getInt { return anInteger; }나 -(void)setInt:(int)newInt { anInteger = newInt; } 같은 중복 코드를 작성하는 건 귀찮고 따분한 일이 아닐 수 없다.@property 명령을 사용하면@property( 쉼표로 구분된 프로퍼티 설정 목록 ) 변수형 변수이름 ;그리고 프로퍼티 선언문은 메서드 선언부에 같이 들어간다.
getter = accessorNamename과 age인 경우, 기본 접근자 이름 역시 name과 age이다.setter = mutatorNameset변수명의 형태가 된다.name과 age일 경우, 기본 변형자 이름은 setName, setAge가 된다. 자동 캐멀 케이싱에 주의할 것.readonly: 접근자만 자동으로 생성되고 변형자는 생성되지 않는다. 이 경우, 아래 메모리 관리 정책은 쓸모가 없다.readwrite: 접근자와 변형자가 자동으로 생성된다.readwrite이다.assign: 변형자는 인자로 받은 값을 인스턴스 변수에 단순 대입한다. 인자로 원시형을 받는 경우에는 반드시 이 선택자를 써야 한다. 인자로 객체를 받는 경우, 이 객체의 생명주기에 전혀 간섭할 수 없다.retain, strong: 변형자의 인자로 받은 객체에 대해 강한 소유권을 행사한다. 원시형에는 이 선택자를 적용할 수 없다. 이 변수가 어떠한 객체를 들고있는 동안 해당 객체는 절대 소멸되지 않는다.copy: 변형자의 인자로 받은 객체를 복제하여 사본 객체를 인스턴스 변수에 넣는다. 원시형에는 이 선택자를 적용할 수 없다. 사본 객체에 대해서는 강한 소유권을 행사한다. 원본 객체의 생명주기에는 간섭하지 않는다.weak: 변형자의 인자로 받은 객체에 대해 약한 소유권을 행사한다. 원시형에는 이 선택자를 적용할 수 없다. 객체는 강한 소유권을 행사하는 주체가 없어지는 즉시 소멸되는데, 이 때 약한 소유권을 행사하는 주체는 모두 nil로 재설정된다.assign이다.nonatomic: 접근자/변형자가 인스턴스 변수에 접근할 때 잠금(lock)을 사용하지 않도록 한다. 다중 스레드 환경에서 사용할 때는 주의하여야 한다. 다만, 읽기 전용(readonly) 프로퍼티에 적용하면 소소하게나마 성능 향상을 꾀할 수 있다.atomic 선택자는 없다. 그냥 nonatomic을 쓰지 않으면 원자적으로(== lock 사용) 동작한다.
@interface Developer: Employee <CoffeeConsuming> {
@private
NSInteger employeeSince;
BOOL fired;
}
// NSString *형의 name.
// 생성되는 접근자: -(NSString *)name;.
// 생성되는 변형자: 생성 안 됨.
// 인스턴스 변수 자동 생성 여부: 생성됨.
// 원자성: 원자적이지 않음.
@property(readonly, nonatomic) NSString *name;
// NSInteger형의 employeeSince.
// 생성되는 접근자: -(NSInteger)employeeSince;.
// 생성되는 변형자: 생성 안 됨.
// 인스턴스 변수 자동 생성 여부: 생성 안 됨.
// 원자성: 원자적임.
@property(readonly) NSInteger employeeSince;
// BOOL형의 fired.
// 생성되는 접근자: -(BOOL)isFired;.
// 생성되는 변형자: -(void)setFired:(BOOL)fireHim;.
// 인스턴스 변수 자동 생성 여부: 생성 안 됨.
// 메모리 관리 정책: 단순 대입.
// 원자성: 원자적이지 않음.
@property(readwrite, nonatomic, getter = isFired) BOOL fired;
// NSArray *형의 thingsToDo.
// 생성되는 접근자: -(NSArray *)thingsToDo;.
// 생성되는 변형자: -(void)assignThingsToDo:(NSArray *)jobs;.
// 인스턴스 변수 자동 생성 여부: 생성됨.
// 메모리 관리 정책: 복제.
// 원자성: 원자적임.
@property(readwrite, copy, setter = assignThingsToDo) NSArray *thingsToDo;
@end
@implementation 클래스 이름역시나
@end 명령으로 @implementation의 영역을 닫는다.@implementation EmptyClass // The Beauty of Emptiness. @end
@implementation ExampleClass
+(char *)iTakeNoParameter {
return "asdf";
}
+(id)allocWithZone:(NSZone *)aZone {
// Vendor specific implementation.
}
-(NSInteger)numberOfCharacter:(unichar)ch inString:(NSString *)str {
NSUInteger j = [str length], k = 0;
unichar *asdf = (unichar *)malloc(sizeof(unichar) * j);
if(NULL == asdf)
return -1;
[str getCharacters:asdf range:NSRangeMake(0, j)];
for(NSUInteger i = 0; i < j; ++i) {
if(ch == asdf[i])
++k;
}
return k;
}
-(void)drawRectangleOfWidth:(CGFloat)w height:(CGFloat)h upperLeftX:(CGFloat)x upperLeftY:(CGFloat)y {
// implementation may vary.
}
@end
@implementation ExampleClass
{ // 인스턴스 변수 선언 시작
int protected; // 역시 기본 가시성은 protected이다. 하지만.......
@public
char inaccessibleFromOutside; // @public 변수가 구현부에 숨어있어서, 외부에서 절대 접근이 불가능하다.
@protected
long protectedButInaccessibleFromChilds; // @protected 변수가 구현부에 숨어있어서, 상속하는 클래스는 접근할 수 없다.
@private
unsigned long long private;
} // 인스턴스 변수 선언 끝
@end