가끔씩 맥이나 iOS 관련 개발 카페등을 보면, 2014년이 시작된 지금까지도 Objective C의 문법중 @synthesize에 관해 물어보는 분들이 계십니다. (참고로, Object C(오브젝트 C) 아닙니다. Objective C(오브젝티브 C) 입니다. 이거 헷갈리시는 분들이 있더군요.)
아마도, 조금 오래된 책으로 공부하거나(최근 책들은 보지 못했습니다만...) 예전에 작성되었던 소스들을 보면서 공부하기 때문인것 같습니다.
그런데, 사실 이제는 2012년 중반 이후로 Modern Objective C가 나온 이후 부터는 @synthesize는 더이상 사용할 일이 거의 없습니다. (정확히 버전은 기억나지 않지만 XCode 4.5정도 이후부터는 Modern Objective C가 지원 될겁니다.)
물론, 예전 소스 분석을 해야 할 일이 많기 때문에 문법 자체는 알아 둬야 합니다만, 사실 개인적으로는 도대체 왜 @synthesize가 존재해서 소스를 지저분하게 만들까 하는 생각도 많이 들었었습니다.
그럼 예전 Objective C에서 사용했던 @synthesize에 대해서 간단히 알아보고 이제는 어떻게 사용하면 되는지 간단하게만 살펴보죠.
<헤더(.h)파일>
@interface MyTestClass : NSObject
{
int myVar; // (1)
}
@property (assign) int myVar; // (2)
- (void) varTest;
<몸체(.m)파일>
@implementation MyTestClass
@synthesize myVar = _myVar; // (3)
- (void) varTest
{
self.myVar = 10;
myVar = 20;
NSLog (@"self.myVar = %i", self.myVar);
NSLog (@"myVar = %i", myVar);
NSLog (@"_myVar = %i", _myVar);
}
자, 이제 varTest를 실행하면 어떤 결과가 나올까요?
self.myVar = 10
myVar = 20
_myVar = 10
이렇게 나옵니다. 왜 이렇게 나오는지 아시겠어요?
(1) self.myVar의 값
먼저 self.myVar는 myVar라는 프로퍼티의 값을 읽어오는 메소드입니다. 정확히는 세터/게터(setter/getter)라고 부르지요. 처음 Objective C를 배우는 분들에 실수하시는게, '.'이라는 연산자가 무조건 접근자인줄 아십니다. 그러나 Objective C에서는 '.'이라는 연산자는 접근자로 쓰일때도 있지만, 프로퍼티를 호출할때는 메서드를 부르는 문법으로 사용됩니다.
따라서 self.myVar 는 [self myVar]와 같은 의미가 됩니다. 변수에 접근하는게 아니라 변수에 대한 값을 쓰거나 읽는 메소드를 호출하는 거예요.
그러면, self.myVar는 바로 myVar 프로퍼티인 (2)의 값을 쓰거나 읽는 메소드를 호출하게 됩니다.
그런데, 위 소스를 보면 myVar 프로퍼티의 값을 읽거나 쓰는 메소드가 없죠? 그런데 어떻게 그런 메소드가 불릴까요?
그 비밀이 바로 @synthesize에 있습니다. 즉, @synthesize myVar; 라고 코드에 적어 놓기만 하면, 컴파일러가 친절하게도 myVar라는 프러퍼티를 @property를 선언할때 사용한 옵션(assign, nonatomic 등등)에 맞는 미리 정의된 게터와 세터 메소드를 자동으로 생성해 주기 때문에, 개발자는 직접 해당 코드를 작성하지 않아도 되는 것입니다.
(2) myVar의 값
그런데, myVar 단독으로는 20이라는 다른 값이 나왔습니다.
이 부분이 처음 시작하시는 분들이 많이들 헷갈리시는것 같은데, myVar와 프로퍼티 myVar는 이름만 같을 뿐 완전히 다른것이 됩니다.
myVar는 인터페이스에서 선언한 멤버변수(1)일 뿐입니다. 즉, self.myVar와 myVar 는 다르다는 말입니다. 위에서도 설명했지만, '.'연산자를 통해 프로퍼티에 접근하는 메소드를 호출하지만, myVar = OOO 이런식으로 단독으로 사용하면, 인터페이스에 선언한 변수가 사용되게 됩니다.
(3) _myVar의 값
(3)의 문법을 보시면, @synthesize myVar = _myVar; 라고 되어있죠? 쉽게 얘기하자면 _myVar는 프로퍼티 myVar에서 사용될 변수의 별칭이라고 보면 됩니다.
즉, 위 소스에서는 프로퍼티인 myVar의 (2)의 이름이 인터페이스에 있는 myVar와 겹쳐져 있는데, (3)과 같이 별칭을 주어서 사실상 프로퍼티인 myVar의 변수 이름을 _myVar로 사용할 수 있게 해 주는 것입니다.
쉽게 생각해서 self.myVar는 _myVar라는 변수를 사용하는 것이고, 따라서 위의 소스에서는 self.myVar를 통해 _myVar에 값을 넣은것과 마찬가지라고 생각하면 쉽습니다.
(다만, 특별한 경우를 제외하고는 프로퍼티는 게터와 세터를 통해 접근해야 안전합니다. 직접 변수에 접근하게 되면, 프로퍼티 옵션에 따라 애써서 만든 게터와 세터를 무시하고 값을 써넣거나 빼내기 때문에 정확하게 사용하지 않으면 문제가 발생할 수 있습니다. 예를 들어 옵션에 retain이나 strong(ARC의 경우)를 사용하면, 세터에는 변수에 값을 넣고 해당 변수를 ratain 하는 코드가 들어 있는데, 직접 값을 써 넣는다면 ratain 하는 코드가 무시되어 버리겠죠?)
그러나....
위와 같이는 쓰지 마세요. 헷갈립니다. 굳이 인터페이스 내의 멤버변수와 프로퍼티 이름을 똑같게 만들어서 헷갈리게 코딩할 이유가 없습니다.
상황에 따라 프로퍼티와 멤버변수중 선택을 하되 같은 이름을 쓰는 일은 피하는게 좋습니다.
그리고....
위 코드 보면 사실 좀 그렇죠. 어차피 프로퍼티를 쓰겠다는건 게터와 세터를 사용하겠다는 건데, 굳이 @synthesize를 코딩해서 손가락 운동을 하게 만들고, 코드 라인을 늘려야 할 이유가 있을까요? 물론 그래야 할 경우가 가끔씩은 있습니다만, 대부분의 경우는 필요가 없습니다.
그래서인지, Modern Objective C에서는 더이상 @synthesize를 사용하지 않아도, 기본적으로 내부에서 @sythesize를 코딩한 것과 같이 해줍니다.
위 코드를 Modern Objective C 형식으로 바꿔 볼까요? 참고로, 위에서 인터페이스 안의 myVar는 빼겠습니다. 이렇게 쓰지 말아라~ 하는 예제였으로....
<헤더(.h)파일>
@interface MyTestClass : NSObject
@property (assign) int myVar;
- (void) varTest;
<몸체(.m)파일>
@implementation MyTestClass
- (void) varTest
{
self.myVar = 10;
NSLog (@"self.myVar = %i", self.myVar);
// NSLog (@"myVar = %i", myVar); // 이 myVar라는 변수가 없으므로 에러나므로 주석처리함
NSLog (@"_myVar = %i", _myVar);
}
뭔가 코드가 깔끔해졌죠?
그렇습니다. 이제 @synthesize를 넣지 않아도 된다는 것입니다.
자, 이제 varTest를 실행하면 어떤 결과가 나올까요?
self.myVar = 10
_myVar = 10
이렇게 나옵니다. self.myVar는 알겠는데, _myVar는 코딩한 적도 없는데 어떻게 나오는걸까요?
네, Modern Objective C에서는 더이상 개발자가 @synthesize를 사용하지 않아도 자동으로 생성을 해주는데요(물론 가끔씩은 직접 코딩해야 할 때도 있습니다.), 자동으로 내부적으로 생성되는 @synthesize 코드에 _myVar를 사용할 수 있게끔 만들어주기 때문입니다.
쉽게 얘기해서 위에는 @synthesize 코드를 넣지 않았지만, 실제로는 @synthesize myVar = _myVar; 라는 코드를 넣은것과 똑같게 동작을 합니다.
쓰다보니 저도 헷갈린 부분이 있지 않았나 걱정이 되는군요.
여하튼, 이제는 간단한 문법이 제공되니 최신 트렌드(?)에 맞게 코딩해 주시면 됩니다.
손가락 운동도 덜해도 되고요.
이 외에도 Modern Objective C에는 편리한 문법이 많습니다. 벌써 나온지 1년반이 넘어가는데도 잘 안쓰시는것 같더라고요.
끝.
'프로그래밍 언어 > Objective C' 카테고리의 다른 글
ARC는 가비지컬렉션이 아니예요. (2) | 2014.01.20 |
---|