Tag Archives: Property

[iPhone] Object-C – Property & Synthesize란 무엇인가?

아이폰의 직접적인 개발에 앞서 Object-C(Objective C)를 공부하다 보면 여러가지 의문점이 드는 부분이 많이 생기는데 그런 부분을 가끔씩이라도 정리하고 넘어가야 하겠다는 생각을 하게 되었습니다. 그런 일환에서 Property와 Synthesize에 대해 알아볼까요. 이 두가지를 이해하기 전에 MVC 개발 방법론에 대해 이해가 필요할 것 같습니다.

iPhone Application Programming Guide문서의 Fundamental Design Patterns에 나와있는 MVC(Model-View-Controller)는 다음과 같이 설명하고 있습니다.

Model-View-Controller(MVC) 디자인 패턴은 기능적인 요소별로 당신의 코드를 나눌 수 있는 방법이다. Model은 당신의 어플리케이션의 기초가 되는 데이터 엔진과 신뢰할 수 있는 데이터를 안전하게 보존 하는 방법을 정의하는 부분이다. View는 당신의 어플리케이션을 위한 사용자 인터페이스(UI)와 그것에게 데이터를 표시하는 암시적인 방법을 정의하는 부분입니다. ControllerModelView사이를 연결하는 다리와 같은 역할을 하며 그들사이의 업데이트를 용이하게 하는 역할을 하는 부분입니다.

번역이 개판이군요. 말을 조금만 정리해 보면 Model은 데이터를 제공하고 보존하는 역할을 하는 영역입니다. View는 실제로 사람이 눈으로 보이고 조작하는 부분입니다. Controller는 모델에서 데이터를 가져와서 가공후에 View에게 전달해주는 비지니스 로직을 포함하는 부분입니다. MVC 개발 방법론은 실제로 하나의 코드를 세가지 영역으로 분리하여 협업 혹은 유지보수에 유리한 환경이 될 수 있도록 하여줍니다.

하지만 아이폰 개발을 하는 상당수가 개인 개발자인것을 생각해 보면 어찌보면 무색한 부분이긴 하군요. Property와 Synthesizie를 이야기 하면서 왜 갑자기 MVC이야기가 나왔을까요? 이들 사이에 밀접한 연관이 있기 떄문입니다. 실제로 Property&Synthesize는 MVC의 Model에 해당합니다. Property는 어플리케이션에 필요한 데이터를 신뢰할 수 있고 안전하게 보존하는데 필요한 룰을 제공합니다. Synthesize는 Property에서 선언한 데이터들을 외부에서 합법적으로 접근할 수 있는 통로를 편리하게 제공하여 줍니다.

우선 다음을 예제 코드를 보도록 하겠습니다. 아래에 대한 의문이 있으시다면 [이글]을 먼저 읽어주세요.

#import <Cocoa/Cocoa.h>

@interface Model : NSObject {
	NSString *data;
}
@property(copy, readwrite) NSString *data;
@end
#import "Model.h"

@implementation Model
@synthesize data;
@end

위와 같이 작성한 코드는 이제 다른 객체에서 다음과 같이 사용할 수 있습니다.

#import <Foundation/Foundation.h>
#import "Model.h"

int main(int argc, const char * argv[]) {
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

	Model * model = [[Model alloc] init];

	// synthesize를 통해 생성된 setter, getter사용법
	[model setData:@"Hello Eye!"];
	NSLog([model data]); // Hello Eye!

	// dot 문법 사용하기
	model.data = @"Bye Eye!";
	NSLog(model.data); // Bye Eye!

	[pool drain];
	return 0;
}

위의 예제에서 알 수 있듯이 model객체의 data 인스턴스 변수에 접근하기 위해서는 synthesize를 통해 생성된 getter(data)와 setter(setData)를 통해 가능합니다. 혹은 C에서 익숙한 객체와 변수사이에 점을 찍는 방식도 사용가능합니다. 하지만 여기서 중요한점은 Property입니다. Model.h의 property선언 부분을 다음과 같이 고쳐볼까요.

@property(copy, readonly) NSString *data;

바뀐점은 readwrite에서 readonly로 바뀌었습니다. 실행해 보면 에러가 발생하는 것을 알 수 있습니다.

error: object cannot be set – either readonly property or no setter found

property와 synthesize를 이용해서 MVC에서 추구하는 데이터를 신뢰할 수 있고 안전하게 사용할 수 있는 방법을 손쉽게 구현할 수 있다는 것을 알게 되었습니다. 여기서 괜히 궁금한것이 생겼습니다. synthesize를 통해서 생성된 setter, getter가 해당 변수를 보호하는 것일까요 property를 통해 정의된 변수 그 자체가 보호하는 것일까요?

이 궁금증을 해소하기 위해 setter를 하나만 만들어 보기로 할까요. 코드에 다음을 추가합니다.

// 현재 @property설정에 readonly로 되어있다고 가정
- (void)setCustomData:(NSString *)myData;
- (void)setCustomData:(NSString *)myData {
	self.data = myData;
}

이제 내가 만든 setCustomData메서드에 메시지를 전달해 보겠습니다.

Model * model = [[Model alloc] init];
[model setCustomData:@"Hello Eye!"];

이 코드를 실행해 보면 아무런 문제가 발생하지 않습니다. 해당 변수가 보호받는것이 아님을 알 수 있습니다. 앞으로는 코드를 작성할 때 @property로 지정한 변수는 될수 있다면 @synthesize를 통해 접근하는 버릇을 들여야 할 것 같습니다.

[iPhone] Object-C : Declared Properties

이번에는 Object-C의 Property에 대해서 이야기를 해볼까 합니다.

어떻게 보면 조금 필요없어 보일수도 있고 어찌보면 MVC(Model, View, Controller)개발 기법과도 밀접한 연관이 있어 보입니다.

하지만 일반적으로 MVC개발에서도 setter/getter로 구성 된 도메인 객체를 따로 두고 있듯이 Object-C에서도 역시 비슷한 구현을 할 수 있는것 같습니다.

Object-C에서 일반적으로 객체의 Property에 접근하기 위해서는 한쌍의 접근자 메서드(getter/setter)를 사용합니다.

이 메서드들을 사용함으로써 객체지향 프로그래밍의 캡슐화(Encapsulation)에 더욱 충실 할 수 있습니다.

관련된 자료는 Object-Oriented Programming with Objective-CMechanism Of Abstraction을 찾아보라고 하는군요.

Property를 정의함으로써 효과적으로 접근자 메서드들을 간략화 시키는 효과를 가져올 수 있습니다.

Property를 사용하기 위해서 일반적으로 @property 지시자와 @synthesize 지시자를 함께 사용합니다.

@property 지시자는 클래스의 @interface 내부에 선언하며 다음과 같은 형식으로 선언합니다.
[code]@property(attributes) type name;[/code]
하나의 Property 선언은 두개의 접근자 메서드와 동일한 기능을 갖습니다.
[code]@proprty float value;[/code]
위의 선언은 다음과 같이 두가지 메서드를 선언한것과 같은 기능을 하게 됩니다.
[code]- (float)value;
– (void)setValue:(float)newValue;[/code]

@property 지시자의 attributes 에는 다음과 같은 정의를 할 수 있습니다.

getter=gettername
기본적으로 Property의 getter 메서드 명은 Property 자신의 이름과 동일 (예 : Property가 foo일 경우 foo)
하지만 이 기본 설정을 내가 원하는 메서드명으로 변경 할 수 있습니다.

setter=settername
Property의 setter 메서드 명은 setPropertyName: 입니다. (예 : Property가 foo일 경우 setFoo:)
역시나 이 기본 설정을 내가 원하는 메서드명으로 변경 할 수 있습니다.

readwrite (DEFAULT)
Property의 값을 읽고 쓸 수 있다는 것입니다. 이 설정은 기본 설정입니다.

readonly
Property의 값을 단지 읽기만 할수 있다고 정의하는 속성입니다.
이 속성은 @implementation 블럭 안에서 오로지  getter 메서드만 필요할 경우에 사용합니다.
@synthesize 지시자를 사용하였을 경우에는 역시나 getter 메서드의 역할만을 하게 됩니다.
값을 대입 하려고 할 경우 에러를 출력하게 됩니다.

assign (DEFAULT)
단순하게 값을 대입합니다. 기본설정입니다. 이전에 어떤 객체를 가리키고 있던 Property라면 이로 인해 해당 객체는 미아가 되어 메모리릭의 주범이 될 수 있습니다. 가비지콜렉터를 사용하지 않는다면 사용을 피해야 합니다.

retain
이것은 assign과 비슷하지만 조금 다릅니다. 이전에 가리키고 있던 객체가 있다면 해당 객체를 Release하여 메모리에서 제거 합니다. 가비지콜렉터를 사용한다면 결과적으로 assign과 동일한 결과를 가지겠지만 좀더 명시적으로 사용해 주면 좋을것 같습니다.

copy
객체를 바로 대입하지 않고 해당 객체의 복사 메서드를 Invoke호출합니다.
그리하여 다른 메모리 영역에 복사본을 만든 다음 그것을 반환하게 됩니다. 이전에 가리키고 있던 값은 Release 시킵니다.

nonatomic
이 속성은 접근자 메서드가 Atomic 하지 않게 동작하게 합니다(?). 기본적으로 접근자는 Atomic하게 동작합니다.
Atomic이라는 말은 멀티스레드 등으로 구성된 프로그램이 특정 접근자 메서드를 호출할때 서로 충돌이 나지 않도록(보통 세마포어니 크리티컬섹션이니 하는 말들 들어보셨을겁니다.) 객체 레벨에서 Lock을 걸고 Property에 접근하게 되는데요 매우 좋은 이야기지만 접근할때 마다 Lock을 걸고 다시 푸는 작업이 반복되므로 퍼포먼스를 떨어뜨리는 결과를 가져오게 됩니다.
이런 접근이 필요없다면 이 속성을 사용하여 Non-Atomic하게 동작하도록 만들어 주시는 것이 좋습니다.

이제 Property에 대해 거의 모든것을 알게 된것 같네요. 이제 예제를 한번 볼까요?
[code]@interface MyClass : NSObject {
    NSString *value;
}
@property(copy, readwrite) NSString *value;
@end

@implementation MyClass
@synthesize value;
@end[/code]
value라는 이름의 Property의 getter 메서드 명은 value이고 setter 명은 setValue입니다.

값을 대입할때 복사가 일어나고 읽고 쓰기를 할 수 있습니다. 또한 nonatomic 속성이 없으니 atomic하게 동작하겠군요.

마지막으로 Property를 사용할때 주의사항이 한가지 있습니다.

객체가 제거 될때 소멸자로 dealloc이 호출되는데 Property들이 자동으로 소거되지 않아 명시적으로 제거해 주셔야 합니다.
[code]- (void)dealloc {
    [value release];
    [super dealloc];
}[/code]