Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Objective-C의 @property, @synthesize, @dynamic에 대해서...

다른 언어와 마찬가지로 Objective-C에서도 객체의 멤버변수를 외부에서 접근하도록 하려면 접근자 메서드(accessor method)인 getter와 setter를 만들어주어야 합니다. Objective-C에서 클래스는 @interface와 @implementation의 2부분으로 나누어지는데 @property는 @interface부분과 연결되고 @synthesize와 @dynamic은 @implementation부분과 연결됩니다. @property와 @synthesize는 preprocessor macro이라서 Xcode에서 Build and Run을 실행했을 때 prewritten/preformatted 코드블락으로 교체됩니다.




@property

@interface Example : NSObject
{
   float value;
}

- (float)value;
- (void)setValue:(float)newValue;

위와같이 프로퍼티에 대한 getter와 setter 메서드를 선언해 줄 수 있습니다. 하지만 이 접근자 메서드를 만들어주는 것은 항상 같은 형태로 반복되는 지루한 작업이기 때문에 Objective-C 2.0에서부터는 @property 지시어를 사용해서 getter와 setter에 대한 코드를 자동으로 생성할 수 있도록 해줍니다.

@interface Example : NSObject
{
   float value;
}

@property float value;


정확한 문법은 @property(attributes [, attribute2, ...]) type name;의 형태이고 앞의 코드에서 6,7라인의 코드대신에 위처럼 @property 지시어를 사용하면 자동으로 앞의 코드로 변환해 줍니다. 위에서 보는 것처럼 getter의 이름은 "프로퍼티이름"이 되고 setter의 이름은 "set프로퍼티이름"이 됩니다. 만약 getter의 이름을 바꾸려면 @property(getter=getValue) float value;와 같이 써주면 getter를 getValue 함수를 써서 사용할 수 있습니다. 프로퍼티를 IB아웃렛으로 지정하려면 @property (nonatomic, retain) IBOutlet NSButton *myButton;와 같이 IBOutlet 식별자를 사용할 수 있습니다.

(attributes [, attribute2, ...])부분에서 사용이 가능한 속성들은 아래와 같습니다.

  • getter=getterName - getter의 이름을 getterName로 지정합니다.
  • setter=setterName - setter의 이름을 setterName로 지정합니다.
  • readwrite - 기본동작으로 getter와 setter를 모두 만듭니다. Mutually exclusive로 readwrite합니다.
  • readonly - getter만 만듭니다. Mutually exclusive로 readwrite합니다. 값을 할당하려고 하면 컴파일 오류가 발생합니다.
  • assign - 기본동작이며 setter가 간단한 할당을 사용합니다.(예 location = where;) 객체를 소유할 필요가 없을때 사용합니다.
  • retain - assign과 비슷하지만 레퍼런스 카운트를 증가시킵니다. Mutually exclusive로 assign과 copy합니다. 포인터객체를 할당할 경우에는 외부에서 객체가 릴리즈되어 파괴된 객체를 참조하는 문제를 막기 위해서 클래스가 멤버객체를 소유하도록 레퍼런스카운트를 증가시킵니다.(이전 값을 release 합니다.)
  • copy - 할당하는데 객체의 복사본을 사용합니다. Mutually exclusive로 assign과 retain합니다. 포인터객체의  경우 레퍼런스의 값이 바뀌어 프로퍼티의 값이 바뀌는 걸 막기 위해 setter에서 복사본을 만들어서 할당하며 copy를 사용하려면 NSCopying 프로토콜을 구현한 객체에서만 유효합니다.
  • nonatomic - 엑세서들을 non-atomic으로 지정합니다. 멀티프로세서 환경해서는 지정해줘야 합니다. 이는 Mutually exclusive락으로 접근자 메서드를 보호하지 말라고 지시하는 것입니다. atomic이 기본동작입니다.




@synthesize
@property를 사용해서 프로퍼티들에 대한 getter와 setter를 선언했으면 @implementation에서 실제 코드를 추가해 주어야 합니다. @property를 사용한 것은 단지 컴파일러가 @implementation에서 getter와 setter메서드가 작성되었다는 것을 기대하도록 하는 것입니다.

@implementation Example
-(float) value
{
    return value;
}

-(void) setValue: (float) newValue
{
    value = newValue;
}
@end

위와 같이 실제 구현코드를 작성해주어야 합니다. 이는 아래코드처럼 @synthesize 지시어를 사용하면 다음과 같이 작성해 줄 수 있습니다.

@implementation Example
@synthesize value;
@end





@dynamic
@dynamic 지시어는 @synthesize대신에 사용할 수 있으며 getter와 setter메서드가 클래스 자신에 의해서 구현되지 않고 (슈퍼클래스같은)다른 어딘가에 구현되어 있다고 알려주어 getter/setter가 구현되어 있지 않아도 컴파일러 경고를 받지 않도록 해줍니다.

Super class :

@property (nonatomic, retain) NSButton *someButton;

@synthesize someButton;

Sub class :

@property (nonatomic, retain) IBOutlet NSButton *someButton;

@dynamic someButton;

위와 같이 작성함으로써 someButton에 대한 구현책임이 델리게이트 되었음을 의미합니다. 혹은 CoreData의 NSManagedObject 클래스처럼 접근자 메서드들이 컴파일타임이 아닌 런타임시의 제공되는 경우에도 컴파일타임에 오류가 나지 않도록 하기 위해서 @dynamic 지시어를 사용할 수 있습니다.
2011/02/27 02:39 2011/02/27 02:39