상수는 변수와 반대되는 의미로 고정된 값을 가졌음을 뜻한다.
Objective-C 에서 상수를 사용하기 위한 방법으로는 const , static const , extern const , #define , enum(NS_ENUM, NS_OPTIONS) 등이 있다.
우선 const 부터 살펴보자.
const 는 선언 시, 단독으로 사용할 지, static 또는 extern 과 함께 사용할 지에 따라 해당 상수의 선언 및 사용 범위(scope)가 달라지게 된다.
헤더 파일에서 static const는 초기화해두었으므로 const와 extern const에 대하여 초기화
constString은 header 에 선언하지 않았으므로 static과 extern에 대해서만 출력
위에서 살펴보듯이 const 는 아래와 같이 구분할 수 있다.
[ const ]
클래스 내부에서만 사용할 전역상수로 사용할 수 있다. 하지만 const만 사용해서 선언하는 일은 없어야 한다. 내부에서 사용할 전역상수 목적일 경우 반드시 static const를 사용해야 한다. 변수가 static으로 선언되지 않으면 컴파일러는 해당 변수를 외부 심벌(external symbol)을 생성하게 되고 다른 파일에서 같은 이름의 변수를 선언하면 링커에서 에러를 일으킨다.
[ static const ]
static const를 결과 내용에서 보듯이 헤더파일에 선언한다면 해당 헤더를 import한 곳에서 공용으로 사용 가능하지만, 구현부에 정의 후 클래스 내부에서 사용할 전역상수로 사용하는 것이 좋다.
왜냐하면 해당 헤더를 #import 한 파일에서 static const 로 선언한 상수와 동일한 변수명을 정의했을 경우 #import 된 static const 값은 무시하고 재정의한 변수명으로 사용되기 때문이다.
[ extern const ]
클래스 외부에서 공용으로 사용할 전역상수로 사용.
static과 다르게 헤더가 아닌 구현부에서만 초기화가 가능하며, 선언부와 동일한 클래스가 아닌 다른 클래스에서 초기화를 할 수도 있으나 찾기 어려워지므로 동일 클래스의 구현부에 정의하는 것이 좋다.
그리고 전역상수의 이름은 연관된 클래스 이름을 접두어로 사용하는 것이 권장된다.
#define은 컴파일 단계에서 미리 정해둔 문자열을 다른 문자열로 바로 치환시키는 형태로 동작한다.
즉 아래와 같이 define을 선언했을 경우
프로그램을 실행하기 전에 #define 문은 컴파일러에 의해 NAVER_URL 이 @"naver.com" 치환되어 처음부터 @"naver.com" 이라고 입력한 것처럼 인식을 하게 된다.
C언어에서 상수를 사용하기 위해 많이 사용하던 방식이지만 Objective-C에서는 권장되지 않는 방식.
일반적으로 많이 인용되던 대답은 "define 매크로는 타입을 체크할 수 없어 런타임 오류가 발생할 수 있기 때문" 이었지만 최근엔 컴파일러가 많이 발전되어 대부분의 타입을 추론하여 사용할 수 있게 되었다.
하지만 이것만은 아니다.
1. static NSString *const variable 과 같은 선언은 그 자체만으로도 좋은 문서 역할을 한다.
2. #define 은 상수 선언이 아닌 단순 대치일 뿐이므로 중간에 실수로라도 변경이 될 위험이 있다.
2. 디버거는 #define macro에 대해 인식하지 못한다. 따라서 디버깅 중 define을 이용해 선언한 매크로키를 이용할 수 없다.
NS_ENUM 과 NS_OPTIONS 은 공용 또는 클래스 내부에서 상수로 사용하기 위해 많이 사용되는 방식 중 하나이다. 다만, const 나 define 방식과 큰 차이가 하나 있는데 NS_ENUM 과 OPTIONS는 결국 정수값만 정의하고 사용할 수 있기 때문이다.
즉, 위와 같이 내부적으로 someEnumString, someEnumDictionary 같이 표현하더라도 실제 값은 정수값을 가진다. 따라서 정수값만 가져도 좋을 상수인 경우는 상관없으나 그렇지 않을 때는 다른 방식을 사용해야 한다는 한계점이 있다.