오브젝티브-C(아이폰과 맥 OS X 개발을 위한)

C
h
a
p
t
e
r
01
Hello Objective-C
『아이폰과 맥 OS 개발을 위한 오브젝티브-C 2.0』
을 읽는 독자에게 환영의 말을 전한다. 이 책은
오브젝티브-C 언어의 기본을 알려주기 위한 책이다. 오브젝티브-C는 C언어의 수퍼셋(superset)
으로 진정한 맥 OS X의 룩앤필(Look & Feel)을 갖는 다양한 애플리케이션에 사용되는 언어이다.
이 책은 오브젝티브-C 언어에 대해 설명하고 그와 관련된 애플의 코코아 툴킷(Cocoa ToolKit)
을 소개한다. 코코아는 오브젝티브-C로 만들어졌으며 맥 OS X의 사용자 인터페이스에 대한 모
든 요소를 포함하고 있다. 일단 이 책에서 설명하는 오브젝티브-C를 배우고 나면 여러분은 코코
아로 진행되는 프로젝트에 빠져들 준비가 된 것이다. 또한 데이브 마크와 제프 라마르쉬가 집필
한『Learn Cocoa on the Mac』또는『Beginning iPhone Development』
『시작하세요,
(
아이폰
프로그래밍』위키북스, 2009)와 같은 책을 볼 준비가 되었다고 할 수 있다.
이 장에서는 이 책을 공부하기 전에 알아야 할 기본 정보를 살펴본 후, 오브젝티브-C의 역사에
대해 살짝 알아보고 앞으로 배울 내용에 대해 간단히 살펴보도록 하자.
시작하기 전에
이 책을 읽으려면 C와 같은 프로그래밍 언어(C++, 자바 등)에 약간의 경험이 있어야 좋다. 어떤
언어이든 해당 언어의 기본 원리를 이해해야 한다. 변수와 함수가 무엇인지 알고 제어문과 반복
문을 사용해서 프로그램의 흐름을 제어할 수 있는 방법을 이해하고 있어야 하는 것이다. 이 책은
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
이런 기본 언어를 바탕으로 오브젝티브-C의 특징과 애플의 코코아 툴킷을 추가적으로 이해하는
데 초점이 맞춰져 있다.
C가 아닌 다른 언어를 알고 있는 상태에서도 이 책을 통해 무리 없이 오브젝티브-C를 배울 수는
있겠지만, 이 책의 부록을 살펴보거나 다른 C언어 기초 도서를 읽어보는 것도 도움이 될 것이다.
미래는 어제로 만들어진다
오브젝티브-C와 코코아는 애플의 맥 OS X 운영체제의 핵심이다. 맥 OS X는 비교적 최근에 만
들어졌지만 오브젝티브-C와 코코아는 훨씬 오래되었다. 1980년대 초에 브래드 콕스(Brad Cox)
는 대중적이고 이식성이 뛰어난 C언어를 우아한 스몰토크(Smalltalk) 언어에 결합시키려는 목적
으로 오브젝티브-C를 만들었다. 1985년에 스티브 잡스(Steave Jobs)는 강력하고 가격이 비싸지
않은 워크스테이션을 만들기 위해 NeXT를 설립하였다. NeXT는 운영체제로 유닉스(UNIX)를
선택하였고, 오브젝티브-C로 만들어진 강력한 사용자 인터페이스 툴킷을 가진 NextSTEP을 만
들게 된다. 그러나 가볍고 멋진 특징을 가지고 있었음에도 불구하고 상업적으로는 성공하지 못
했다.
1996년에 애플이 NeXT를 인수했을 때(혹은 그 반대로 NeXT가 애플을 인수했다고 하는 이들도
있음) NextSTEP은 코코아로 이름이 바뀌었고 더 많은 매킨토시 프로그래머를 불러들이게 된다.
애플은 코코아를 포함한 개발 툴을 무료로 배포하였기 때문에 맥 프로그래머들은 이런 개발 툴
을 무료로 사용하는 덕을 보게 되었다. 따라서 여러분은 약간의 프로그래밍 경험, 오브젝티브-C
의 기본 지식 그리고 배우려는 열정만 있으면 된다.
어쩌면 여러분은「오래된 유닉스는 둘째치더라도 오브젝티브-C와 코코아는 외계인 알프와 A
특공대(외화 시리즈) 시절인 80년대에 개발됐는데 너무 오래되고 진부한 도구는 아닐까?」
라고
생각할 수도 있겠다. 그러나 결코 그렇지 않다. 오브젝티브-C와 코코아는 뛰어난 프로그래머로
구성된 팀이 수년간 노력하여 만들어낸 결과물이며 지속적으로 업데이트되면서 발전하고 있다.
시간이 지날수록 오브젝티브-C와 코코아는 놀랍도록 우아하고 강력한 툴로 진화하고 있다. 또
한 오브젝티브-C는 아이폰용 애플리케이션을 개발하기 위한 핵심 도구이기도 하다. 그렇기 때
문에 NeXT가 오브젝티브-C를 적용한 후로 20여 년간 모든 훌륭한 개발자들이 오브젝티브-C
와 코코아를 계속 사용하고 있는 것이다.
14
1장. Hello Objective-C
앞으로 배울 것들
오브젝티브-C는 C언어의 수퍼셋이다. 오브젝티브-C는 C에서 시작하였지만 다른 여러 중요한
특징을 C에 추가한 형태이다. C++ 또는 자바를 살펴본 경험이 있다면 오브젝티브-C가 실제로
얼마나 작은지 보고 놀라게 될 것이다. 이 책의 각 장에서는 C에 추가된 오브젝티브-C의 내용에
대해 자세히 알아본다.
■ 2장 C의 확장은 오브젝티브-C를 소개하는 기본 내용에 중점을 두고 있다.
■ 3장 객체 지향 프로그래밍의 소개는 객체 지향 프로그래밍의 기본적인 내용을 설명한다.
■ 4장 상속은 부모 클래스의 특징을 가지고 있는 클래스를 만드는 방법에 대해 설명한다.
■ 5장 컴포지션은 객체들이 결합돼서 함께 동작할 수 있도록 하는 방법을 알아본다.
■ 6장 소스 파일 구성에서는 프로그램 소스를 만들기 위한 실제 전략을 알아본다.
■ 7장 Xcode에 대하여에서는 여러분이 프로그래밍을 할 때 도움을 주기 위해 몇 가지 팁과
Xcode에 능숙해지기 위한 방법을 보여준다.
■ 8장 Foundation Kit 소개는 코코아의 주요 프레임워크 두 개 중 하나를 사용해서 코코아의
멋진 특징을 알아본다.
■ 9장 메모리 관리에서는 코코아 애플리케이션을 다루는 데 중점을 둔다.
■ 10장 객체 초기화에서는 객체가 만들어질 때 어떠한 일이 일어나는지를 살펴본다.
■ 11장 프로퍼티에서는 오브젝티브-C에서 새롭게 사용하는 점(.) 표기법의 비밀을 알아보고 객
체 접근자를 쉽게 만드는 방법을 살펴본다.
■ 12장 카테고리에서는 이미 존재하고 있는 클래스(여러분이 작성하지 않은 클래스일지라도)에
새로운 메소드를 추가할 수 있는 오브젝티브-C의 특이한 특징을 설명한다.
■ 13장 프로토콜에서는 클래스를 구현하는데 필요한 내용을 알려주도록 하는 오브젝티브-C에
서 상속의 한 형태에 대해 설명한다.
■ 14장 AppKit 소개에서는 또 다른 주요 프레임워크를 사용해서 코코아로 멋진 애플리케이션
을 개발할 수 있는 방법을 알아본다.
■ 15장 파일 불러오기와 저장하기에서는 데이터를 저장하고 가져오는 방법을 알아본다.
■ 16장 키-밸류 코딩은 여러분의 데이터를 간접적으로 다루는 방법을 알아본다.
■ 17장 NSPredicate에서는 데이터를 어떻게 자르는지 알아본다.
15
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
자바나 C++같은 다른 종류의 언어만 경험해 봤거나 윈도우나 리눅스 같은 다른 플랫폼의 경험
만 있다면 부록의 다른 언어에서 오브젝티브-C로를 살펴보도록 하자. 이 내용으로 오브젝티
브-C를 알기 위해 필요한 것들을 정리할 수 있다.
요약
맥 OS X 프로그램은 1980년대부터 사용되어 지금은 강력한 툴로 진화된 오브젝티브-C로 만들
어진다. 이 책은 여러분이 C 프로그래밍을 어느 정도 알고 있다는 가정 하에 시작한다. 그럼 즐
거운 여행이 되길 바란다!
16
C
h
a
p
t
e
r
02
C 의확장
오브젝티브-C는 C언어에 약간의 내용이 추가된 것이 전부다. 그래서 멋지다! 이 장에서는 우선
간단한 오브젝티브-C 프로그램을 만들어 보면서 C언어에서 추가된 내용을 알아본다.
가장 간단한 오브젝티브-C 프로그램
여러분은 이미 전통적인 Hello World 프로그램(Hello World! 또는 그 비슷한 간단한 단어를 출
력하는 기본 프로그램)의 C버전에 접해 보았을 것이다. Hello World는 보통 초보 C 프로그래머
가 배우는 첫 번째 프로그램이다. 우리는 전통을 무시할 생각이 없으므로 여기서도 Hello
Objective-C라고 하는 비슷한 프로그램을 작성해 보겠다.
Hello Objective-C 빌드하기
이 책에서는 여러분이 애플의 Xcode 툴을 이미 설치했다고 가정하겠다. 만일 Xcode가 없거나
사용해 본 경험이 없다면 홈페이지에서 제공하는 Objective-C.zip 파일의 Xcode. pdf를 참조
하여 Xcode를 얻는 법과 설치하는 법을 배울 수 있다(http://www.bjpublic.co.kr의 도서자료 ▶
다운로드).
여기서는 여러분의 첫 번째 오브젝티브-C 프로젝트를 만들기 위해 Xcode를 사용하는 단계에
대해 설명하므로 이미 Xcode에 익숙하다면 넘어가도 좋다. 시작하기 전에, 이 책의 사이트에서
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
Objective-C.zip 파일을 내려 받아 푼다. 압축을 풀고 나면 Learn Objective-C Samples라는
폴더가 생긴다. 이 프로젝트는 예제 폴더 02.01 Hello Objective-C에 들어 있다.
이제 프로젝트를 만들기 위해 Xcode를 시작하자. Xcode는 /Developer/Applications에서 찾
을 수 있다. 쉽게 사용하기 위해 Dock에 Xcode 아이콘을 넣어놓도록 하겠다.
일단 Xcode가 시작됐으면 File ▶ New Project를 선택한다. Xcode에서 만들 수 있는 다양한
종류의 프로젝트 목록이 나올 것이다. 다른 프로젝트 타입은 상관하지 말고 그림 2-1에 나타낸
대로 윈도우의 왼편에 있는 Command Line Utility를 선택하고 나서 오른편에 있는
Foundation Tool을 선택한다. 그리고 Choose 버튼을 클릭한다.
그림 2-1 새로운 Foundation Tool 만들기
Xcode는 시트(sheet)를 보여주고 프로젝트의 이름을 무엇으로 저장할지 물어본다. 원하는 아무
이름이나 넣어도 되지만 우리는 그림 2-2에 보이는 것처럼「Hello Objective-C」
라고 하겠다.
여기서는 이 프로젝트를 깔끔하게 관리하기 위해 Projects 디렉터리에 넣었지만 여러분은 원하
는 폴더 아무 곳에나 넣어도 된다.
Save 버튼을 클릭하고나면 Xcode는 프로젝트 윈도우(그림 2-3 참조)라고 하는 메인 윈도우를
보여준다. 이 윈도우는 소스 편집 창을 포함한 프로젝트를 구성하는 여러 부분을 보여준다. 선택
되어 있는 Hello Objective-C.m 파일이 Hello Objective-C를 위한 코드를 포함하고 있는 소
스 파일이다.
18
2장. C의 확장
Hello Objective-C.m은 어디서 많이 본 코드를 담고 있는데, Xcode에는 친절하게도 새로운 프
로젝트마다 제공하는 기본 코드가 들어 있다. 우리는 Hello Objective-C 프로그램을 Xcode가
제공하는 이 샘플 코드보다 더 알아보기 쉽게 만들 수 있다. Hello Objective-C.m의 모든 코드
를 지우고 다음의 코드로 바꾸도록 하자.
#import <Foundation/Foundation.h>
int main (int argc, const char *argv[])
{
NSLog (@"Hello, Objective-C!");
return (0);
} // main
그림 2-2 새로운 Foundation Tool의 이름을 정한다.
지금은 여기에 있는 모든 코드가 이해되지 않는다고 걱정하지는 말자. 곧 이 프로그램을 한 줄씩
자세히 살펴볼 것이다.
소스 코드는 실제로 프로그램을 실행해서 확인할 수 없다면 재미가 없다. Build and Go 버튼을
클릭하거나
+R 을 눌러서 프로그램을 빌드하고 실행하자. 오타가 없다면 Xcode는 이 프로그
램을 컴파일하고 링크하고 나서 실행까지 한다. Run ▶ Console을 클릭하거나
+Shift +R 을
눌러서 Xcode의 콘솔 윈도우를 실행해 보자. 콘솔은 그림 2-4처럼 이 프로그램의 출력을 보여
준다.
19
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
그림 2-3 Xcode의 메인 윈도우
그림 2-4 Hello Objective-C의 실행 모습
드디어 결과를 보게 됐다. 여러분의 첫 번째 오브젝티브-C 프로그램이다. 축하한다! 자, 이제 각
부분을 나눠서 어떻게 동작하는지 살펴보자.
Hello Objective-C 분해하기
다시 Hello Objective-C.m의 내용을 살펴보자.
#import <Foundation/Foundation.h>
int main (int argc, const char *argv[])
{
NSLog (@"Hello, Objective-C!");
20
2장. C의 확장
return (0);
} // main
Xcode는 오브젝티브-C 코드가 들어 있는 파일임을 나타낼 때 .m이라는 확장자를 사용한다. 이
파일은 오브젝티브-C 컴파일러에 의해 처리된다. .c로 끝나는 파일이름은 C 컴파일러가, .cpp
파일은 C++ 컴파일러가 처리한다. Xcode에서는 이 모든 컴파일이 GNU Compiler
Collection(GCC)에 의해 처리되는데, 하나의 컴파일러로 이 세 가지 다른 언어를 모두 처리할
수 있다.
main.m 파일은 코드가 두 줄 들어있는데, C를 알고 있다면 어렵지 않을 것이다. 앞의 코드를 보
면 main() 선언으로 시작해서 return(0) 구문으로 끝난다. 오브젝티브-C는 그 속이 C와 똑같
기 때문에 main() 함수를 선언하고 값을 반환하는 문법은 C와 동일하다. 이 부분을 제외한 나머
지 코드가 일반적인 C와 약간 달라 보일 것이다. 예를 들어, 저 낯선 #import라는 것은 무엇일
까? 궁금한가? 계속 읽어보자!
N O T E
.m 확장자는 원래 오브젝티브-C가 처음 소개됐을 때 메시지(message)를 나타냈는데, 메시지는 앞으
로 우리가 공부할 오브젝티브-C의 중요 특징을 나타낸다. 요즘은 메시지라고 읽지 않고 그냥 .m(점엠)
파일이라고 부른다.
낯선 #import
오브젝티브-C도 C처럼 구조체, 상수, 함수 원형과 같은 요소에 대한 선언을 담고 있는 헤더 파
일(header file)을 사용한다. C에서는 필요한 정의에 대한 헤더 파일을 컴파일러에게 알려주기
위해 #include 문을 사용한다. 오브젝티브-C에서도 이런 목적으로 #include를 사용할 수 있지
만 실제로는 사용하지 않게 될 것이다. 대신 다음과 같이 #import를 사용한다.
#import <Foundation/Foundation.h>
#import는 Xcode가 오브젝티브-C나 C, 또는 C++ 프로그램을 컴파일할 때 사용하는 GCC 컴
파일러가 제공하는 특징이다. #import는 그 파일에서 실제로 #import가 같은 헤더 파일을 여러
번 포함해도 헤더 파일이 한 번만 포함된다는 것을 보장한다.
21
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
N O T E
C에서 프로그래머는 하나의 파일이 두 번째 파일을 포함하고 두 번째 파일이 다시 첫 번째 파일을 포함
하는 경우에 재선언을 방지하기 위해서 보통 #ifdef 지시자를 사용하도록 구성한다.
오브젝티브-C에서는 프로그래머가 #import를 사용함으로써 이런 문제를 해결하고 있다.
#import <Foundation/Foundation.h>문은 컴파일러에게 Foundation 프레임워크에서
Foundation.h 헤더 파일을 찾아보라고 알려준다.
그럼 프레임워크란 무엇인가? 궁금해 할 줄 알았다. 프레임워크는 여러 부분(헤더 파일, 라이브
러리, 이미지, 사운드 등)이 모여서 하나의 단위로 묶여 있는 컬렉션이다. 애플은 코코아, 카본
(Carbon), 퀵타임(QuickTime), OpenGL 등의 기술을 프레임워크로 배포한다. 코코아는
Foundation과 Application Kit(AppKit이라고도 한다)의 두 프레임워크로 구성되어 있으며, 코
코아를 더 멋지게 만들어 주는 코어 애니메이션(Core Animation)과 코어 이미지(Core Image)
를 포함하는 프레임워크도 들어있다.
Foundation 프레임워크는 자료구조와 통신 메커니즘 등과 같이 사용자 인터페이스의 하위에
있는 내용을 다룬다. 이 책의 모든 프로그램은 Foundation 프레임워크를 기반으로 한다.
N O T E
이 책을 다 읽은 독자가 코코아의 달인이 되기 위한 다음 과업은 코코아의 상위 레벨 기능인 사용자 인
터페이스, 프린팅, 컬러와 사운드 관리, 애플스크립트(AppleScript) 지원 등을 담고 있는 Application
Kit에 통달하는 것이다. 더 많이 알고 싶은 사람에게는 곧 번역서로도 출간될 예정인 데이브 마크와 제
프 라마르쉬의『Learn Cocoa on the Mac』
을 추천한다.
각 프레임워크는 여러 기술의 커다란 집합체이며 종종 수십 또는 수백 개의 헤더 파일을 포함하
고 있고 프레임워크의 각 헤더 파일 모두를 포함하는 마스터 헤더 파일을 가지고 있다. 마스터
헤더 파일에 #import를 사용하면 프레임워크의 모든 기능에 접근할 수 있다.
Foundation 프레임워크를 위한 헤더 파일은 거의 1MB의 디스크 용량을 차지하고 수백 개의 파
일에 걸쳐있는 14,000줄 이상의 소스 코드를 포함한다. 여러분이 #import <Foundation/
Foundation.h>로 Foundation 프레임워크의 마스터 헤더 파일을 포함했다면 이 거대한 내용을
사용할 수 있게 된다. 어쩌면 각 파일의 모든 텍스트를 포함하는데 컴파일러가 상당한 시간이 들
거라고 생각할 수도 있겠지만, Xcode는 똑똑하다. Xcode는 #import할 때 빠르게 로드되는 헤
22
2장. C의 확장
더의 형태로 압축하고, 군더더기를 빼서 만든 미리 컴파일된 헤더를 사용해서 작업의 속도를 높
인다.
만일 Foundation 프레임워크로 어떤 헤더 파일들을 포함하게 되는지 궁금하다면 헤더 폴더
(/System/Library/Frameworks/Foundation.framework/Headers/) 안의 내용을 살펴보도록
하자. 이 폴더의 파일을 살펴볼 때는 파일을 지우거나 변경하지 않는 것이 좋다.
NSLog( )와 @"문자열"
Foundation 프레임워크를 위한 마스터 헤더 파일에 #import를 사용해서 포함했으니 이제는 코
코아 기능의 일부를 이용하는 코드를 만들 준비가 된 것이다. Hello Objective-C에서 실제로
사용된 처음이자 유일한 라인이 다음과 같은 NSLog() 함수이다.
NSLog (@"Hello, Objective-C!");
이 함수는「Hello, Objective- C!」
를 콘솔에 출력한다. C에 대한 경험이 조금이라도 있다면 아
마도 printf() 함수에 대한 경험이 있을 것이다. NSLog()는 printf()와 아주 비슷한 기능을 하
는 코코아 함수이다.
printf()와 마찬가지로 NSLog()도 첫번째 인수로 문자열을 받아들인다. 이 문자열은 %d와 같
은 형식 기술자를 포함할 수 있고, 함수는 형식 기술자와 같은 추가 파라미터를 받는다.
printf()는 출력하기 전에 문자열에 이 추가 파라미터를 끼워 넣는다.
이전에 이야기했듯이 오브젝티브-C는 아주 약간 특별한 양념을 친 C와 같기 때문에 원한다면
NSLog() 대신 printf()를 그냥 쓸 수도 있다. 그러나 시간과 날짜가 함께 출력되는 기능이나
새 라인 문자(\n)를 자동으로 넣어주는 등 부가적인 기능이 있으니 NSLog()를 사용하기를 추천
한다.
NSLog()라는 함수 이름이 좀 낯설게 느껴질 수 있다. 함수 이름의「NS」
는 무슨 의미일까? 읽다
보면 코코아의 모든 함수, 상수, 타입(type) 이름에 NS가 앞에 붙는 것을 볼 수 있다. 이 접두사
는 함수가 다른 툴킷에서 온 것이 아니라 코코아에서 왔다는 것을 알려준다.
이런 접두사는 같은 식별자가 두 개의 다른 대상에 쓰일 때 결과적으로 큰 문제가 되는 이름 충돌
(name collisions) 사태를 막는데 도움이 된다. 만일 코코아가 Log()라는 이름의 함수를 가지고 있
다면, 이를 잘 알지 못하는 프로그래머가 어딘가에서 만든 Log()라는 함수와 이름이 충돌할 수 있
다. Log() 함수를 가지고 있는 프로그램이 코코아를 포함하여 빌드되면 Xcode는 Log()가 여러 번
23
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
정의되었다고 투덜댈 것이고 좋지 않은 결과, 즉 에러가 나타난다.
이제 접두사를 사용하는 것이 왜 좋은지 알게 되었다. 그런데 이번에는 다른 의문이 생길 것이
다. 예를 들어, 왜 Cocoa를 접두사로 쓰지않고 NS를 사용했을까? NS 접두사는 이 툴킷이
NextSTEP이라고 불리며 NeXT Software(공식적으로는 NeXT, Inc.로서 1996년에 애플에 합병
됨)의 제품이었던 때로 거슬러 올라간다. NextSTEP을 위해 이미 작성된 코드와의 호환을 유지
하기 위해, 애플은 NS 접두사를 계속 쓰고 있다.
코코아는 접두사 NS에 대해서 엄격하게 관리하기 때문에, 당연히 여러분이 작성한 변수나 함수
의 이름에는 NS라는 접두사를 사용하지 말아야한다. 만약 사용하게 되면 여러분이 작성한 코드
를 읽는 사람들이 그 코드가 원래 코코아에 들어 있는 것인지 아닌지 헷갈리게 된다. 아울러 애
플에서 코코아에 여러분이 만든 함수와 같은 이름의 함수를 추가하게 되면, 그 코드는 앞으로 제
대로 동작하지 않게 될 수도 있다. 코코아는 그 외의 접두사는 따로 관리하지 않으니 여러분이
원하는 접두사를 골라서 쓸 수 있다. 많은 사람들은 코드 작성자의 이름이나 회사의 이름 이니셜
을 접두사로 사용한다. 우리의 예제를 조금 더 단순하게 만들기 위해서 이 책에서는 접두사를 사
용하지 않을 것이다.
자, NSLog()문의 다른 부분에 대해서도 살펴보자.
NSLog (@"Hello, Objective-C!");
문자열 앞에 있는 기호에 주목해 보자. 책을 만들 때 실수로 들어간 글자가 아니다. 골뱅이(@,
at) 기호는 표준 C언어에 추가된 오브젝티브-C의 특징 중 하나이다. 큰따옴표 사이의 문자열 앞
에 골뱅이가 있는데, 이는 큰따옴표 안의 문자열을 코코아 NSString의 요소로 처리해야 한다는
의미이다.
그럼 NSString 요소라는 것은 무슨 뜻일까? NSString에서 NS 접두사를 떼고 보면 그냥 String
이라는 친숙한 단어가 남는다. 여러분이 이미 알고 있는 것처럼 String은 문자열이고, 문자열은
보통 사람이 읽을 수 있는 문자의 나열이다. 따라서 NSString은 코코아에서 문자의 나열을 의미
함을 알 수 있을 것이다.
NSString 요소는 상당히 많은 수의 기능을 담고 있으며 코코아에서 문자열이 필요한 곳이면 언
제 어디서나 사용된다. 다음은 NSString의 기능을 몇 가지 간추려본 것이다.
■ 문자열의 길이를 알려줌
■ 다른 문자열과의 비교
24
2장. C의 확장
■ 정수 또는 실수로의 값 변환
NSString은 C의 문자열보다 더 많은 일을 할 수 있다. NSString의 설명 및 사용법은 8장에서
자세히 알아보도록 하겠다.
NSString이 좋은 점이 여기서도 드러난다. 바로 이름 자체가 코코아의 멋진 특징 중 하나라는
것이다. 대부분 코코아의 구성요소들은 매우 직관적인 방식으로 이름이 정해지는데, 해당 구성
요소가 구현된 특징을 설명하도록 노력하고 있다. 예를 들어 NSArray는 배열(array)을 제공하고,
NSDateFormatter는 여러 방식으로 날짜의 형식을 바꿀 수 있도록 해 주며, NSThread는 멀티 스
레드 프로그래밍을 하는 도구를 제공하고, NSSpeechSynthesizer는 말소리를 들을 수 있도록
한다.*
이제, 우리의 첫 번째 프로그램으로 다시 돌아가자. 프로그램의 마지막 라인은 main() 함수의
실행을 끝내는 return 문이고 프로그램을 종료한다.
return (0);
0 값은 우리의 프로그램이 성공적으로 끝났다는 것을 나타내는 반환값이다. 이 부분은 C의
return 문이 동작하는 것과 같다.
다시 한 번 축하한다! 여러분은 방금 첫 번째 오브젝티브-C 프로그램을 작성하였고, 컴파일을
했으며, 실행해 보고 분석까지 해 봤다.
불리언 타입을 알고 있는가?
다양한 언어가 불리언(Boolean) 타입을 가지고 있다. 이 불리언은 참(true)과 거짓(false) 값을
저장하는 변수를 위한 타입이다. 오브젝티브-C라고 해서 다를 것은 없다.
C에는 true와 false 값을 담을 수 있는 불리언 데이터 타입으로 bool이 있다. 오브젝티브-C도
YES와 NO를 저장할 수 있는 BOOL이라는 비슷한 타입을 제공한다. 그런데 오브젝티브-C의 BOOL
타입은 C의 bool 타입보다 10년은 먼저 만들어졌다. 이 두 개의 다른 불리언 타입은 같은 프로
그램에서 같이 쓸 수 있지만 코코아 코드를 작성하는 경우에는 BOOL을 사용하게 될 것이다.
* 역주 : 맥은 기본적으로 TTS(텍스트 음성 변환, Text to Speech)가 들어있으며 제공 소프트웨어인 기본「텍스트 편집
기」
에서 문장을 입력한 후 읽을 수 있다.
25
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
N O T E 다음 문자열을 살펴보자
자주 하는 실수 중 하나는 NSLog()에 NSString @"strings" 대신에 C 스타일의 문자열을 넣는 경우이
다. 그렇게 하면 컴파일러는 다음과 같은 경고를 내보낸다.
main.m:46: warning: passing arg 1 of 'NSLog' from incompatible pointer type
이 프로그램을 실행하면 제대로 실행되지 않는다. 이런 문제를 잡기 위해서는 Xcode가 경고를 에러로
간주해서 메시지를 뿌리도록 설정하는 것이 좋다. 그렇게 설정하려면 Xcode의 왼쪽 창 Group & Files
에 있는 목록에서 가장 위에 있는 아이템을 선택하고 메뉴의 File ▶ Get Info를 선택한 후 Build 탭을
선택한다.* 그리고 나서 아래 그림처럼 검색 필드에 error라고 입력하고 가장 아래 Treat Warning as
Errors의 체크박스를 선택한다. 그리고 좀 전에 error를 검색한 필드 왼쪽 Configuration에서 가장 위
에 있는 All Configurations를 선택하면 된다.
실전에 강한 BOOL
실전에 강한 BOOL을 보여주기 위해 두 정수 값이 같은지, 다른지 비교하는 프로젝트(예제 폴더
02.02 BOOL Party)로 넘어가 보자. main() 함수 이외에도 이 프로그램은 두 개의 함수를 정의
하고 있다. 우선 areIntsDifferent() 함수는 두 개의 정수 값을 받아서 BOOL 값을 반환하는데,
두 정수가 다르다면 YES, 두 정수가 같으면 NO를 반환한다. 두 번째 함수 boolString()은 BOOL
파라미터를 받아서 파라미터가 YES인 경우는 @"YES"를, NO인 경우는 @"NO"를 반환한다. 이런
함수는 BOOL 값을 사람이 읽을 수 있는 형태로 출력하고 싶을 때 쓸 수 있는 함수이다. main()
* 역주 : 이 과정은 Xcode에서 왼쪽 창의 Group & Files의 바로 아래 있는 Hello Objective-C 프로젝트를 더블 클릭
하여 동일하게 실행할 수 있다.
26
2장. C의 확장
NO T E
오브젝티브-C에서 BOOL은 실제로 8비트의 저장 공간을 갖는 부호 있는 문자(signed char) 타입을 단
지 형 정의(typedef)한 것이다. YES는 1로 정의되어 있고 NO는 0으로 정의되어 있다(#define 사용).
오브젝티브-C는 BOOL을 YES나 NO의 값만을 담을 수 있는 진정한 불리언 타입으로 여기지 않는다. 컴파
일러는 BOOL을 8비트 숫자로 인식하고 YES와 NO의 값은 단지 관습이다. 이는 미묘한 결과를 낳는다. 만
일 무심코 1바이트보다 큰 값의 정수(예를 들어 short나 int 값 등)를 BOOL 변수에 넣는다면, BOOL 변
수의 값에서 하위 바이트만 사용한다. 하위 바이트가 0인 경우(예를 들어 8960, 16진수로 0x2300 등)
BOOL 값은 0, 즉 NO값이 된다.
함수는 두 정수를 비교하고 그 결과를 출력하는데 이 두 함수를 사용한다.
Bool Party를 위한 프로젝트 생성도 Hello Objective-C 프로젝트를 만드는 과정과 동일하다.
1. Xcode가 실행되고 있지 않은 상태라면 Xcode를 실행한다.
2. File ▶ New Project를 선택한다.
3. 왼쪽에서 Command Line Utility를 선택하고 나서 오른쪽에 Foundation Tool을 선택한다.
4. Choose를 선택한다.
5. Project Name을 Bool Party라고 입력하고 Save 버튼을 클릭한다.
Bool party.m 파일을 다음과 같이 수정한다.
#import <Foundation/Foundation.h>
// returns NO if the two integers have the same
// value, YES otherwise
BOOL areIntsDifferent (int thing1, int thing2)
{
if (thing1 == thing2) {
return (NO);
} else {
return (YES);
}
} // areIntsDifferent
// given a YES value, return the human-readable
// string "YES". Otherwise return "NO"
NSString *boolString (BOOL yesNo)
27
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
{
if (yesNo == NO) {
return (@"NO");
} else {
return (@"YES");
}
} // boolString
int main (int argc, const char *argv[])
{
BOOL areTheyDifferent;
areTheyDifferent = areIntsDifferent (5, 5);
NSLog (@"are %d and %d different? %@",
5, 5, boolString(areTheyDifferent));
areTheyDifferent = areIntsDifferent (23, 42);
NSLog (@"are %d and %d different? %@",
23, 42, boolString(areTheyDifferent));
return (0);
} // main
방금 작성한 프로그램을 빌드해서 실행해 보자. 출력을 보기 위해 Run ▶ Console을 선택하거
나 키보드 단축키
+Shift +R 을 사용해서 Console 윈도우를 띄울 필요가 있다. Run
Debugger Console 윈도우에 다음과 같이 출력되는 것을 볼 수 있을 것이다.
2008-07-20 16:47:09.528 02 BOOL Party[16991:10b] are 5 and 5
different? NO
2008-07-20 16:47:09.542 02 BOOL Party[16991:10b] are 23 and 42
different? YES
The Debugger has exited with status 0.
다시 한 번 이 프로그램을 함수 단위로 나눠서 어떻게 동작하는지 알아보자. 우리가 알아볼 첫
번째 함수는 areIntsDifferent() 함수이다.
BOOL areIntsDifferent (int thing1, int thing2)
{
if (thing1 == thing2) {
return (NO);
} else {
28
2장. C의 확장
return (YES);
}
} // areIntsDifferent
areIntsDifferent() 함수는 두 정수 파라미터를 받아서 BOOL 값을 반환한다. C에 경험이 있다
면 문법은 익숙할 것이다. thing1을 thing2와 비교하는 부분을 볼 수 있을 것이다. 만일 같으면,
NO를 반환한다. 다른 경우에는 YES를 반환한다. 상당히 직관적이다. 그렇지 않은가?
두 번째 함수는 boolString()이다. 이 함수는 숫자 BOOL 값을 사람이 읽을 수 있는 문자열로 바
꿔준다.
N O T E 쉽게 오해할 수 있는 불리언
경험 많은 C 프로그래머라면 areIntsDifferent() 함수를 다음과 같이 한 줄로 쓸 수도 있다.
BOOL areIntsDifferent_faulty (int thing1, int thing2)
{
return (thing1 - thing2);
} // areIntsDifferent_faulty
이들이 이렇게 작성할 수 있는 것은 0이 아닌 값이 YES라는 가정을 하기 때문이다. 그러나 이 경우는
다르다. 이 함수가 반환하는 값은 C에서는 참 또는 거짓이지만 BOOL을 반환하는 함수의 호출자는 YES
나 NO가 반환되기를 기대한다. 만일 프로그래머가 이 함수를 다음과 같이 사용한다면 23 빼기 5가 18이
기 때문에 실패한다.
if (areIntsDifferent_faulty(23, 5) == YES) {
// ....
}
위 함수가 C에서는 참 값일 수 있겠지만, 오브젝티브-C에서 YES(1의 값)와는 다르다. BOOL 값을 바로
YES와 비교하지 않는 것이 좋다(비교하려면 상당히 주의를 기울여 처리해야 한다). 왜냐하면 너무나 영
리한 프로그래머들도 가끔은 areIntsDifferent_faulty()와 비슷한 위험한 시도를 하기 때문이다. 대
신 다음과 같이 if문을 쓰자.
if (areIntsDifferent_faulty(5, 23)) {
// ....
}
이에 반해 NO를 바로 비교하는 것은 안전한데, C에서 false는 0 하나밖에는 없기 때문이다.
29
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
NSString *boolString (BOOL yesNo)
{
if (yesNo == NO) {
return (@"NO");
} else {
return (@"YES");
}
} // boolString
함수의 가운데 있는 if 문은 이제 놀랄 것이 못 된다. 단지 yesNo를 상수 NO와 비교해서 같은 경
우 @"NO"를 반환한다. 그렇지 않으면 yesNo가 반드시 참 값이 되어야 하기 때문에 @"YES"를 반
환한다.
boolString() 함수의 반환 타입이 NSString을 가리키는 포인터라는 사실에 주의하자. 이는 전
에 NSLog()를 처음 봤던 코코아 문자열의 하나를 반환하는 함수라는 것을 의미한다. 반환문을
살펴보면 반환 값의 바로 앞에 골뱅이 기호가 있는 것을 볼 수 있다. 이것이 NSString 값이라는
결정적인 증거이다.
main() 함수는 마지막 함수이다. main() 함수의 반환 타입과 인수의 선언을 준비한 다음에 로
컬 BOOL 변수가 있다.
int main (int argc, const char *argv[])
{
BOOL areTheyDifferent;
areTheyDifferent 변수는 areIntsDifferent()가 반환하는 YES 또는 NO 값을 담는다. 우리는
단순하게 함수의 BOOL 반환 값을 if 문처럼 직접 사용할 수 있지만 코드를 읽기 쉽게 하기 위해
서 여기처럼 추가변수를 사용하는 것도 좋은 방법이다. 깊게 중첩된 구조는 이해하기 힘든 경우
가 많다. 아울러 이런 곳은 버그가 숨어 있기 좋은 장소이기도 하다.
자기 자신의 비교
다음 두 줄의 코드는 areIntsDifferent()로 두 정수를 비교해서 areTheyDifferent 변수에 반
환값을 저장한다. NSLog()는 숫자 값과 boolString() 함수에 의해 반환되는, 사람이 읽을 수
있는 형태의 문자열을 출력한다.
areTheyDifferent = areIntsDifferent (5, 5);
30
2장. C의 확장
NSLog (@"are %d and %d different? %@",
5, 5, boolString(areTheyDifferent));
이미 이전에 본 것처럼 NSLog()는 형식 문자열을 받아서 형식 식별자에 꽂아 넣을 수 있는 추가
파라미터를 사용하는 기본적인 코코아식 printf() 함수이다. 위에서 NSLog() 호출에서 두 개의
5로 치환되는 두 개의 %d를 볼 수 있다.
NSLog()에 전달한 문자열의 끝에 또 하나의 골뱅이 기호가 있다. 여기서는 바로 %@이다. 무슨
의미일까? boolString() 함수는 NSString 포인터를 반환한다. printf()는 NSString이 어떻
게 동작하는지 모르기 때문에 우리가 사용할 수 있는 형식 지정자가 없다. NSLog()를 만든 사람
들은 문자열에서 문자를 사용하고 콘솔에 출력하도록 보내는 NSString처럼 적절한 인수를 받아
들이는 NSLog() 명령에 %@ 형식 지정자를 추가했다.
N O T E
아직 객체에 대해 설명하지는 않았지만, 여기서 간단히 살펴보자. NSLog()를 사용해서 어떤 객체의 값
을 출력할 때, %@ 형식 지정자를 사용한다. 이 식별자를 사용할 때, 객체는 description이라는 이름의
메소드를 통해 자신의 NSLog() 형식을 제공한다. NSString의 description 메소드는 단순히 문자열의
문자들을 출력한다.
다음 두 줄은 방금 본 것과 상당히 비슷하다.
areTheyDifferent = areIntsDifferent (23, 42);
NSLog (@"are %d and %d different? %@",
23, 42, boolString(areTheyDifferent));
함수가 23과 42 값을 비교한다. 이번에는 두 값이 다르기 때문에 areIntsDifferent()는 YES를
반환하고 사용자는 23과 42가 다른 값이라는 사실을 나타내는 문자열을 보게 된다.
다음은 BOOL Party의 최종 결론을 보여주는 return 문이다.
return (0);
} // main
이 프로그램에서 여러분은 오브젝티브-C의 BOOL 타입과 참과 거짓 값을 나타내는 상수인 YES
와 NO를 살펴보았다. int와 float 등의 타입을 사용하듯 BOOL을 변수, 함수의 파라미터, 함수의
31
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
반환값으로 사용할 수 있다.
요약
이 장에서 여러분은 처음으로 두 개의 오브젝티브-C 프로그램을 만들어 보고 재미있다는 사실
을 알게 됐다. 또한 컴파일러에 같은 헤더를 한 번만 포함하도록 하도록 알려주는 #import와 같
은 언어의 오브젝티브-C 확장도 약간 알아보았다. NSString 문자열에 대해서도 배웠는데,
@"hello"처럼 문자열 앞에 골뱅이가 붙는다. NSLog() 함수라는 중요하고 여러 용도로 쓰일 수
있는 도구도 보았는데, 이는 콘솔에 텍스트를 출력하기위해 코코아가 제공하는 함수이다. 또한,
NSLog()의 특수한 형식 지정자 %@는 NSLog() 출력에 NSString을 출력할 수 있도록 한다. 그리
고 코드에서 골뱅이 기호가 나오면 이는 바로 C언어의 오브젝티브-C 확장을 의미하는 암호라는
것도 알게 되었다.
그럼 한눈 팔지 말고, 객체 지향 프로그래밍의 신비한 세계를 다루게 될 다음 장을 기대하시라!
32
A
p
p
e
n
d
i
x
부록
다른언어에서
오브젝트- C로
다른 언어에 익숙해져 있는 많은 프로그래머들이 문법이나 개념이 달라서 오브젝티브-C를 새롭
게 배우는 데 어려움을 겪는다. 오브젝티브-C를 새롭게 배우는 프로그래머들은 자신이 사용하
던 언어에서는 가능한 무엇과 무엇과 무엇을 지원하지 않는다고 불평을 하기도 한다. 그렇다면
오브젝티브-C의 기능 목록을 확인하는 것은 일단 제쳐 두고 직접 한번 부딪혀 봐라. 오브젝티
브-C가 특정 부분에서만 약간 이상하게 보일 뿐이라는 것을 바로 알 수 있을 것이다.
다른 플랫폼과 언어에서 오랜 경험이 있는 프로그래머를 포함해 오브젝티브-C와 코코아를 새롭
게 배우는 프로그래머들을 위한 조언이 있다면, 오브젝티브-C, 코코아, Xcode에서 사용하는 단
어는 그냥 그대로 받아들이는 것이 좋다는 것이다. 몇 권의 책이나 튜토리얼을 읽으면서 공부하
여 일단 오브젝티브-C에 대한 경험이 생기면, 그동안 사용하던 다른 언어와 오브젝티브-C/코
코아를 비교하면서 서로 어떤 부분이 강점인지를 알게 될 것이다. 모든 상황에 맞는 이상적인 언
어란 없으며 어떤 툴킷도 모든 일에 완벽히 대응하지 못한다. 가장 좋은 것은 여러분이 특정 언
어와 툴킷을 충분히 배워서 어떤 작업에 어떤 도구가 필요한지, 장점을 얻는 대신 치러야 할 대
가는 없는지를 제대로 알고 있는 것이 중요하다.
이 장에서는 다른 언어에서 오브젝티브-C로 옮기는데 필요한 정보를 제공하도록 하겠다.
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
C언어 사용자
오브젝티브-C는 이미 쓰이고 있는 C언어에 단지 객체 지향을 처리하기 위한 몇 가지 기능을 추
가한 것뿐이다. 이 책의 많은 부분이 이런 추가 부분에 대해 다루고 있으므로 C의 기본적인 내용
을 반복하지는 않겠다. 그러나 몇 가지 주제에 대해서는 알아볼 필요가 있다.
오브젝티브-C 프로그래머들은 표준 C 라이브러리와 같은 C의 강점을 그대로 사용할 수 있다는
것을 기억하자. 예를 들면 메모리를 동적으로 할당하기 위한 malloc()과 free() 또는 파일 처
리를 위한 fopen()과 fgets()를 사용할 수 있다.
코코아 메일링 리스트에는「콜백을 사용하는 ANSI C 라이브러리를 호출하고 있습니다. 이 함수
대신 메소드를 사용할 수 있나요?」
라는 질문이 자주 올라온다. 이 질문은 하위 레벨의 코어 파운
데이션(Core Foundation)이나 코어 그래픽스(Core Graphincs)와 같은 애플 프레임워크를 사
용할 때도 많이 나온다.
이 질문에 짧게 대답하자면「사용할 수 없다」
이다. 콜백은 그 라이브러리에 의해 요구되는 시그
너처(signature)를 갖는 함수에서만 동작한다. 오브젝티브-C 메소드를 구현하는 함수는 self와
selector 인수가 우선 필요하기 때문에 필요한 시그너처와는 결코 일치하지 않게 된다.
대부분의 콜백 기반의 라이브러리는 사용자 데이터 또는 포인터를 제공하도록 한다. 여러분은
이것이 여러 정보를 가리고 있는 큰 바위라서 그 뒤는 보이지 않는다고 생각할 수 있다. 콜백을
등록할 때 어떤 정보를 가지고 있는 포인터를 그 라이브러리에 전달할 수 있고, 그 라이브러리는
콜백이 호출됐을 때 포인터를 돌려준다.
모든 오브젝티브-C 객체는 동적으로 할당되기 때문에 콘텍스트(context) 포인터로 객체의 주소
를 사용해도 안전하며 스택에 할당된 객체에 대해 걱정할 필요는 없다. 콜백 안에서, 콘텍스트
포인터를 객체 타입으로 캐스팅하고 메시지를 보낸다.
예를 들어 C API로 된 XML 파싱 라이브러리를 사용하고 있다고 해 보자. XML 파일이 파싱되는
TreeWalker라는 클래스에 데이터를 보낸다. 새 TreeWalker를 생성하자.
TreeWalker *walker = [[TreeWalker alloc] init];
그리고 XML 파서를 만든다.
XMLParser parser;
352
부록. 다른 언어에서 오브젝트 C로
parser = XMLParserLoadFile ("/tmp/badgers.xml");
파서를 위한 콜백 함수(C 함수)를 설정하고 콘텍스트로 TreeWalker 객체를 사용한다.
XMLSetParserCallback (parser, elementCallback, walker);
그러면 XML 파일이 파싱되고 콜백이 호출된다.
void elementCallback (XMLParser *parser,
XMLElement *element,
userData *context)
{
TreeWalker *walker = (TreeWalker *) context;
[walker handleNewElement: element
inParser: parser];
} // someElementCallback
콘텍스트 포인터가 객체 포인터로 캐스팅되는 것을 볼 수 있고 그 객체로 메시지가 보내진다.
C++ 사용자
C++은 다중 상속, 네임스페이스, 연산자 오버로딩, 템플릿, 클래스 변수, 추상 클래스,
STL(Standard Template Library) 등 오브젝티브-C가 지원하지 않는 기능을 많이 가지고 있다.
이런 기능이 그리울 수도 있는데, 오브젝티브-C는 이런 기능을 대치하거나 최소한 흉내낼 수 있
는 기술을 가지고 있다.
예를 들어, 다중 상속 또는 추상 클래스의 구현을 위해서는 카테고리와 프로토콜을 사용할 수 있
다. 일반적으로 다중 상속을 사용하는 이유는 인터페이스를 제공해서 다른 코드가 객체에 있는 특
정 메소드를 실행할 수 있도록 하려고 하는 것이다. 카테고리와 프로토콜은 이런 상황에 딱 맞다.
또한 여러분은 순수 추상 베이스 클래스를 제공하기 위한 용도로도 프로토콜을 사용할 수 있다.
카테고리와 프로토콜은 C++에서 멤버 변수(member variable)라고 하는 추가 인스턴스 변수를
가져오는 다중 상속에서는 도움이 되지 않는다. 이 작업을 하기 위해서는 하나의 객체에서 다른
객체를 포함하고 메시지를 두 번째 객체에 연결하는 스텁(stub) 메소드를 사용하기 위한 컴포지
353
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
션을 사용할 수 있다. 자바에서는 이 방법이 일반적인 기술이다. 아울러 forwardInvocation:
메소드를 오버라이드함으로써 다중 상속을 흉내낼 수도 있다. 이 메소드는 객체가 처리할 수 없
는 메시지를 받은 경우에 호출된다. NSInvocation 객체를 살펴봄으로써「다중 상속된」객체에
전달돼야 하는지를 알 수 있고, 필요한 경우에는 메시지를 보낸다. 이 테크닉은 많은 스텁 메소
드를 작성해야 한다는 부담을 없애준다. 그러나 실제 다중 상속에 비해 속도가 느리고 설정하는
데 힘들 수도 있다.
C++의 네임스페이스와 같은 기능을 대치하기 위해 오브젝티브-C의 네임 프리픽스(frefixes)와
같은 기능이 있기는 하지만 C++에 비하면 매우 미약하다. 그렇긴 하더라도 오브젝티브-C는
C++의 여러 기능을 대치하고 있다.
C++ vtable vs. 오브젝티브-C 다이내믹 디스패치
C++과 오브젝티브-C의 가장 다른 점 중 하나가 바로 C++에서는 멤버 함수(member function)
라고 불리우는 디스패칭 메소드의 메커니즘이다. C++은 가상 함수(virtual function)에서 어떤
코드가 실행되어야 하는지 결정하기 위해서 vtable에 기반을 둔 메커니즘을 사용한다.
각 C++ 객체는 함수 포인터의 배열을 가리키는 포인터를 가지고 있다고 생각할 수 있다. 컴파일
러는 실행하길 원하는 가상 함수 코드를 봤을 때 vtable의 시작 위치부터의 오프셋을 계산하고,
vtable의 시작부터의 오프셋에 있는 함수 포인터를 갖는 머신 코드를 뽑고 실행하기 위해서 그
코드를 사용한다. 이 프로세스는 컴파일러가 컴파일할 때(compile time) 멤버 함수를 호출하는
객체의 타입을 알아서 vtable로부터의 정확한 오프셋 위치를 계산할 수 있어야 한다. 이런 종류
의 디스패치는 상당히 빠르다. 포인터 연산 몇 개와 함수 포인터를 얻기 위해 한 번 읽는 작업이
면 된다.
3장에서 자세히 설명한 오브젝티브-C의 방식은 실행하려는 다양한 클래스에서 코드를 찾기 위
해 런타임 함수를 사용한다. 이 테크닉은 C++의 방식에 비해서는 몇 배나 느리다.
오브젝티브-C는 속도와 안전성이라는 전통적인 선택의 관점에서 보면 유연함과 편리함을 제공
한다. C++ 모델의 멤버 함수 디스패치는 빠르고, 아울러 컴파일러와 링커가 사용되는 객체가 메
소드를 확실하게 처리할 수 있기 때문에 안전하기도 하다. 그러나 C++ 메소드는 여러분이 다루
는 객체의 종류를 실제로 바꿀 수 없기 때문에 유연하지는 못하다. 같은 메시지에 대해서 다른
객체의 클래스가 반응하게 하기 위해서는 상속을 사용해야만 한다.
인스턴스 체인, 클래스를 구성하는 멤버 등 클래스에 대한 많은 정보를 C++컴파일러는 유지해
354
부록. 다른 언어에서 오브젝트 C로
주지 않는다. 런타임에는 일반적으로 객체를 다루는 능력이 제한된다. 여러분이 런타임에 할 수
있는 것은 객체가 다른 객체의 특정 서브클래스라는 것을 알려주는 다이내믹 캐스트 정도이다.
C++ 상속 계층은 실행 시간에 바뀔 수 없다. 프로그램이 한번 컴파일되고 링크되면 돌처럼 바뀌
지 않는다. 유닉스 링커를 사용해 동작하므로 안전을 위해서 사용하는 이름 만드는 규칙(C++
name mangling)이 복잡하여 C++ 라이브러리의 다이내믹 로딩은 종종 문제가 될 수 있다.
오브젝티브-C에서는 객체가 호출될 수 있는 상태로만 구현되어야 하며, 이런 메소드는 임의의
객체가 다른 객체의 데이터 소스 또는 델리게이트가 될 수 있도록 한다. 다중 상속의 부재는 불
편할 수는 있지만, 객체의 상속 족보에 대한 걱정 없이 어떤 객체든지 메시지를 보낼 수 있는 능
력은 장점이 된다.
물론, 아무 객체에나 메시지를 보내는 기능은 오브젝티브-C를 C++보다는 덜 안전하게 만든다.
여러분이 어떤 객체에 핸들링하지 못하는 메시지를 보내면 런타임 에러를 보게 될 것이다. 코코
아에는 타입에 안전한 컨테이너가 없다. 어떤 객체도 컨테이너에 들어갈 수 있다.
오브젝티브-C는 클래스에 대한 많은 메타 데이터를 가지고 다니기 때문에 객체가 어떤 메시지
에 대해 반응하는지를 알 수 있다. 이런 관습은 데이터 소스나 델리게이트를 가지고 있는 객체에
게는 상당히 일반적이다. 메시지에 대해 반응하는 델리게이트가 있는지를 점검하는 것으로 앞으
로 얻을 수 있는 에러를 피할 수 있다. 아울러 카테고리를 사용해서 다른 클래스에게 메소드를
추가할 수도 있다.
이 메타 데이터 때문에 프로그램에서 사용된 클래스를 해킹하기가 쉽다. 여러분은 인스턴스 변
수, 객체 구조에서 이 변수의 배치, 클래스에 정의된 메소드 등을 결정할 수 있다. 실행파일에서
디버깅 스페이스 정보를 제거한다고 해도 오브젝티브-C의 메타데이터는 사라지지 않는다. 노출
하기 위험한 알고리즘을 사용하고 있다면 C++을 사용해 구현하거나, 최소한 그 메소드 이름이
라도 노출되지 않도록 만들어 놓아야 한다. 이름만 들어봐도 어떤 기능을 하는지 알 수 있는
SerialNumber Verifier 등의 클래스 이름이나 메소드 이름은 사용하지 말자.
오브젝티브-C에서는 nil 객체에 메시지를 보낼 수 있다. 여러분이 메시지를 보낼 객체가 NULL
인지를 확인할 필요가 없다. nil에 메시지를 보내는 작업은 실제로는 아무 일도 하지 않는 코드
로 치환된다. nil에 메시지를 보낸 결과 값은 그 메소드의 반환 타입에 따라 다르다. 그 메소드가
포인터 타입이면 반환 값은 nil이 된다(nil 객체에 메시지를 안전하게 보낼 수 있다는 것을 의미
한다). 만일 메소드가 포인터의 크기와 같은 int이거나 더 작은 경우는 0을 반환한다. 그리고
float이거나 구조체를 반환한다면 정의되지 않은 결과를 갖게 된다. 이 때문에 객체 포인터가
355
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
NULL인지를 확인하는 nil 객체 패턴(보통 Null Object Pattern이라고 함)을 사용할 수 있다. 반
면에 이 nil 객체 패턴 테크닉은 찾기 어려운 버그와 에러를 만들 수 있다.
오브젝티브-C에서 모든 객체는 동적으로 할당된다. 스택 기반의 객체, 임시 객체의 자동 생성/
소멸, 클래스 타입의 자동 타입 변환이 없기 때문에 C++의 스택 기반 객체보다는 무겁다. 이것
이 오브젝티브-C에서 NSPoint와 NSRange와 같은 가벼운 것들을 객체로 사용하지 않고 구조체
로 사용하는 이유 중 하나이다.
마지막으로 오브젝티브-C는 매우 느슨한 언어이다. C++는 public, protected, private 멤버 변
수와 멤버 함수를 가지고 있지만 오브젝티브-C는 기본적인 protected 인스턴스 변수를 약간 지
원할 뿐이다. 쉽게 우회적으로 할 수는 있지만 멤버 함수를 보호하지는 않는다. 메소드 이름을
알고 있는 사람은 누구든지 객체에 그 메시지를 보낼 수 있다. 여러분은 오브젝티브-C의 리플렉
션(reflection) 기능을 사용해서 주어진 객체가 지원하는 모든 메소드를 볼 수 있다. 헤더 파일에
없는 메소드라 할지라도 호출될 수 있고, 메시지 전달은 C의 함수에서 올 수 있기 때문에 어떤
객체가 그 메소드를 호출하는지 알 수 있는 방법이 없다.
지금까지 살펴본 것처럼 서브클래스에서 메소드를 재선언할 필요가 없다. 학계에서는 이것이 좋
은지에 대한 두 가지 논쟁이 있다. 한 부류는 재선언은 수퍼클래스에 어떤 변화가 있었는지를 읽
는 이에게 정보를 제공한다고 말하는 부류이고, 다른 부류는 클래스 사용자는 이런 내용에 신경
쓰고 싶어 하지 않으며 새 메소드가 오버라이드되었을 때 의존성이 있는 모든 클래스의 재컴파
일을 유발할 가치는 없다고 말한다.
오브젝티브-C는 클래스 변수가 없다. 파일의 범위를 갖는 글로벌 변수를 사용해서 그 변수에 접
근하는 접근자 메소드를 만드는 것으로 클래스 변수를 흉내낼 수 있다. 예제 클래스의 선언이 다
음과 같다고 하자. 인스턴스 변수와 메소드 선언이 포함되어 있다.
@interface Blarg : NSObject
{
}
+ (int) classVar;
+ (void) setClassVar: (int) cv;
@end // Blarg
그리고 구현은 다음과 같다.
356
부록. 다른 언어에서 오브젝트 C로
#import "Blarg.h"
static int g_cvar;
@implementation Blarg
+ (int) classVar
{
return (g_cvar);
} // classVar
+ (void) setClassVar: (int) cv
{
g_cvar = cv;
} // setClassVar
@end // Blarg
코코아 객체 상속 계층은 공통 조상 클래스를 갖는데, 바로 NSObject이다. 새 클래스를 생성했
을 때 거의 대부분 NSObject나 기존 코코아 클래스의 서브클래스를 만든다. C++ 객체 상속 계
층은 다른 구별되는 뿌리로부터 몇 개의 가지를 갖는 경향이 있다.
오브젝티브-C++ 사용자
오브젝티브-C와 오브젝티브-C++ 모두를 사용할 수 있는 방법이 있다. Xcode에 같이 들어있
는 GCC 컴파일러는 오브젝티브-C++라고 하는 하이브리드 언어를 지원한다. 이 컴파일러는 몇
개의 제한 사항만을 제외하고는 C++와 오브젝티브-C 코드를 자유롭게 섞어 사용할 수 있도록
해준다. 필요한 경우, 이 방법을 사용해서 타입 안전성과 하위 레벨의 성능을 얻을 수 있고, 오브
젝티브-C의 동적인 특징과 코코아 툴킷도 적절히 사용할 수도 있다.
일반적인 개발 스페이스 시나리오는 애플리케이션의 핵심 로직은 이식성이 좋도록 만들어진
C++ 라이브러리(만일 크로스 플랫폼 애플리케이션을 작성하는 경우)로 만들고, 플랫폼의 툴킷
을 사용하는 사용자 인터페이스를 따로 작성하는 것이다. 오브젝티브-C++는 이런 형식의 개발
과정에 아주 적합하다. C++의 성능과 타입 안정성을 보장받으면서 그 플랫폼에 맞는 사용자 인
터페이스를 보장받을 수 있다.
컴파일러가 오브젝티브-C++로 코드를 인식하려면 소스 코드의 확장자를 .mm로 사용해야 한
다. .M 확장자도 동작하지만 맥의 HFS+ 파일 시스템은 대소문자를 가리지 않기 때문에 시스템
에 따라 문제를 일으키지 않으려면 .mm을 사용하는 것이 좋다.
357
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
물질과 반물질처럼 오브젝티브-C와 C++ 객체 계층은 섞일 수 없다. 그러므로 NSView를 상속
받은 C++ 클래스를 가질 수 없고, std::string을 상속받은 오브젝티브-C 클래스를 가질 수
없다.
여러분은 C++ 객체에 오브젝티브-C 객체를 가리키는 포인터를 넣을 수 있다. 모든 오브젝티
브-C 객체들은 동적으로 할당되기 때문에 클래스에 완전히 내장되거나 스택에 선언된 객체는
가질 수 없다. 여러분이 만든 C++ 생성자에서 오브젝티브-C 객체를 alloc하고 init할 필요가
있고, 소멸자(또는 다른곳)에서 이 객체를 릴리즈할 필요가 있다. 그러므로 다음은 유효한 클래
스 선언이다.
class ChessPiece {
ChessPiece::PieceType type;
int row, column;
NSImage *pieceImage;
};
오브젝티브-C 객체에 C++ 객체를 넣을 수 있다.
@interface SWChessBoard : NSView
{
ChessPiece *piece[32];
}
@end // SWChessBoard
오브젝티브-C 객체에 내장된 C++객체(포인터를 갖는다)는 오브젝티브-C 객체가 할당될 때 생
성자가 호출되어야 하며, 오브젝티브 객체의 dealloc 메소드가 호출될 때 소멸자가 호출되어야
한다.
자바 사용자
C++처럼 자바 또한 오브젝티브-C가 가지고 있지 않거나 다른 방식으로 구현된 다양한 기능을
가지고 있다. 예를 들어 전통적인 오브젝티브-C는 가비지 컬렉터가 없지만 참조/릴리즈와 오토
릴리즈 풀이 있다. 물론 여러분이 원한다면 오브젝티브-C 프로그램에서 가비지 컬렉션을 켤 수
도 있다.
자바 인터페이스는 한 무리의 메소드를 구현해야 한다는 면에서는 오브젝티브-C의 공식 프로토
358
부록. 다른 언어에서 오브젝트 C로
콜과 비슷하다. 자바는 추상 클래스를 가지고 있지만 오브젝티브-C는 가지고 있지 않다. 자바는
클래스 변수를 가지고 있지만 오브젝티브-C는 바로 위의 C++ 언어 사용자의 예에서 본 것처럼
파일 스코프의 글로벌 변수를 만들어서 접근자 메소드를 사용해 구현할 수 있다. 오브젝티브-C
는 public과 private 메소드의 구분이 없다는 면에서는 매우 느슨한 언어이다. 우리가 언급한 대
로 객체가 지원하는 어떤 메소드도 실행될 수 있다. 헤더 파일에 없는 경우라도 마찬가지다. 자
바는 final로 클래스를 선언해서 서브클래스가 사용하는 것을 막을 수 있다. 오브젝티브-C는
실행 시간에 클래스에 메소드를 추가할 수 있는 기능을 지원한다.
오브젝티브-C에서의 클래스 구현은 보통 헤더 파일과 구현 파일, 두 개의 파일로 나눠 구성된
다. 이 방법이 필수 사항은 아니지만, 이 책에 있는 것과 같은 작은 클래스에 적합하다. 헤더 파
일(.h 확장자를 갖는 파일)은 enum, 자료형, 구조체, 이 클래스의 코드가 사용하는 코드 등 그 클
래스와 관련 있는 정보를 담는다. 구현 부분 #import를 사용해서 전처리기로 이 헤더 파일을 포
함하게 된다. 자바는 C의 전처리기가 없다(전처리기는 컴파일러에 내용이 전달되기 전에 C, 오
브젝티브-C, C++에서 먼저 자동으로 매크로를 처리해 주는 툴이다). #로 시작하는 지시자를 봤
다면 그 줄은 전처리기에 명령을 전달하라는 것임을 알 수 있다. C 전처리기는 실제로는 C 계열
언어에 대해 모른다. 단지 텍스트를 치환해 줄 뿐이다. 전처리기는 매우 강력한 툴이며, 그렇기
때문에 위험한 툴이기도 하다. 많은 프로그래머들이 전처리기의 부재가 자바의 특징이라고 생각
하고 있다.
자바에서는 거의 모든 에러가 예외 처리로 처리된다. 오브젝티브-C에서는 에러 처리가 여러분
이 사용하는 API에 따라 다르다. 유닉스 API는 보통 -1 값을 반환하고 특정 에러에는 errno라
고 하는 전역 에러 번호가 설정된다. 코코아 API는 보통 프로그래머 에러이거나 정리가 불가능
한 상황에서 예외를 던진다. 오브젝티브-C 언어는 자바나 C++의 @try, @catch, @finally와
비슷한 예외 처리 방법을 제공한다.
오브젝티브-C에서는 null 객체를「nil」이라고 한다. nil에 메시지를 보낼 수 있고
NullPointerException에 대해 걱정할 필요가 없다. 또한 nil에 메시지를 보낼 때 NULL에 메
시지를 보내는지 검사하지 않아도 된다. nil에 메시지를 보내는것은 C++ 사용자 관련 절에서 이
미 알아보았다.
오브젝티브-C에서는 카테고리를 사용해 기존 클래스에 메소드를 추가함으로써 실행 시간에 클
래스의 동작을 바꿀 수 있고, final 클래스 같은 것이 없기 때문에 어떤 클래스든 헤더 파일만 있
다면 서브클래스를 만들 수 있다. 컴파일러가 객체의 수퍼클래스 정의를 알아야 클래스의 크기
를 계산할 필요가 있기 때문에 헤더는 있어야 한다.
359
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
사실상 오브젝티브-C에서는 자바보다 서브클래스를 만드는 일이 적다. 카테고리와 어떤 객체든
메시지를 보낼 수 있도록 해주는 동적 런타임 같은 메커니즘을 통해서 보다 적은 수의 클래스에
기능을 넣을 수 있고, 그 클래스에 기능을 넣는 것이 이치에 맞다. 예를 들어, NSString에 문자
열을 뒤집거나 공백을 제거하는 등의 기능을 추가하기 위한 카테고리를 넣을 수 있다. 그러면 그
NSString이 어디서 왔는지 걱정할 필요 없이 NSString에서 그 메소드를 실행할 수 있다. 이런
기능을 제공하기 위해 여러분 자신의 문자열 서브클래스를 제한하지 않는다.
보통 코코아에서 서브클래스가 필요한 경우는 객체 계층의 가장 위에 완전히 새로운 객체를 만
들어야 하는 경우이거나, 어떤 객체의 동작을 기본적으로 바꿔야 하거나 상속받자마자 바로 사
용할 수 있는 것이 없기 때문에 반드시 서브클래스를 만들어야 하는 클래스를 만들 때이다. 예를
들어, 코코아에서 사용자 인터페이스 컴포넌트로 사용되는 NSView 클래스는 drawRect: 메소
드를 구현하고 있지 않다. 여러분이 NSView의 서브클래스를 만들어서 그림이 그려지는 뷰
(view)에 그리는 메소드를 오버라이드할 필요가 있다. 그러나 대부분의 객체를 위해 델리게이
션, 데이터 스페이스 소스가 사용된다. 오브젝티브-C는 어떤 객체건 메시지를 보낼 수 있기 때
문에 객체는 특정한 서브클래스가 될 필요가 없고 특정 인터페이스를 따를 필요도 없으므로, 하
나의 클래스는 어떤 수의 다른 객체의 델리게이트와 데이터 스페이스 소스가 될 수 있다.
데이터 스페이스 소스와 델리게이트 메소드가 카테고리에 선언되었기 때문에 그 모두를 구현할
필요는 없다. 오브젝티브-C에서의 코코아 프로그래밍은 스텁 메소드 또는 공식 프로토콜을 적
용할 때, 단지 컴파일러의 에러를 없애기 위해 임베디드된 객체에 있는 것과 같은 메소드를 실행
하는 메소드가 거의 없다.
물론 힘은 권리가 아닌 의무에서 나온다. 오브젝티브-C의 수동 참조, 릴리즈, 오토릴리즈 메모
리 관리 시스템을 사용하면 메모리 에러가 나기 쉽다. 다른 클래스에 카테고리를 넣는 것은 상당
히 강력한 메커니즘이지만, 남용할 경우 다른 사람들이 이해하지 못하는 코드를 만들 수 있다.
아울러 오브젝티브-C는 C에 기반을 두기 때문에 전처리기의 위험한 부분이나 포인터를 사용해
서 발생하는 메모리 에러 등 C의 짐을 고스란히 가지고 있다.
BASIC 사용자
많은 프로그래머들이 비주얼 베이직(Visual Basic)과 리얼베이직(REALbasic)의 사용법을 알고
있다. 이런 언어를 사용했던 프로그래머들이 오브젝티브-C와 코코아로 옮겨가면 당황해 할 수
있다.
360
부록. 다른 언어에서 오브젝트 C로
베이직(비주얼/리얼) 환경은 완벽하게 동작하는 통합 개발 환경을 제공한다. 코코아는 개발 환경
을 인터페이스 빌더(Interface Builder)와 Xcode 두 부분으로 나눴다. 사용자 인터페이스를 만
들고 특정 객체에서 실행되는 메소드의 이름을 사용자 인터페이스에 알려주기 위해서는 인터페
이스 빌더를 사용하고, 제어 로직을 소스코드에 편집하기 위해서는 Xcode(또는 TextMate,
BBEdit, emacs 또는 여러분이 좋아하는 텍스트 에디터)를 사용한다.
베이직은 사용자 인터페이스 아이템과 코드가 밀접하게 통합되어 있다. 여러분이 원하는 대로
동작시키기 위해 버튼과 텍스트 필드에 소스 코드를 넣는다. 일반 클래스에 이런 코드를 넣고 버
튼이 그 클래스와 연결되어 동작하도록 할 수 있겠지만, 베이직 프로그램은 대부분 사용자 인터
페이스 객체에 직접 코드를 써 넣는다. 주의하지 않는다면 이런 형식은 수많은 서로 다른 아이템
들의 로직으로 인해 프로그램이 너저분해질 수 있다. 베이직 프로그래밍은 보통 여러분이 원하
는 동작을 하도록 객체의 속성을 바꾸도록 되어 있다.
코코아에서는 인터페이스와 그 인터페이스 아래에서 동작하는 로직을 분명히 나눠 놓은 것을 볼
수 있다. 코코아는 서로 상호작용하는 객체들의 모임을 가지고 있고 객체의 설정을 하는 대신 객
체에게 속성을 바꿔달라고 요청한다. 이런 구분은 별 차이 없어 보이지만 매우 중요하다. 여러분
이 코코아에서 많은 시간을 소요하게 될 부분은 어떤 설정이 필요한지를 고민하는 것이 아닌, 어
떤 메시지를 보내야 하는지를 고민하는 것이다.
베이직은 서드파티 콘트롤이 상당히 많고 코드 지원도 많다. 여러분이 직접 코드를 만드는 것보
다는 그런 서드파티의 코드를 이용하는 경우도 많이 있다.
스크립트 사용자
펄, PHP, 파이선, Tcl 등 기존의 스크립트 사용자들은 오브젝티브-C나 코코아로 옮겨 가기가
가장 힘들 것이라고 느낄 것이다.
스크립트 언어는 문자열 처리, 자동으로 처리되는 메모리 관리(참조횟수를 관리하거나 가비지
컬렉션을 사용할 수도 있지만 스크립트 사용자는 상관하지 않는다), 개발 시간의 단축, 유연한
타입 처리(숫자와 문자, 배열 같은 것들을 쉽게 다른 타입으로 바꿀 수 있다), 다운로드해서 사용
할 수 있는 다양한 패키지 등을 지원함으로써 프로그래머의 편의성을 높여 준다. 스크립트 언어
의 런타임 환경도 아주 유연해서 언제든지 객체의 타입을 설계하고 구조체들을 제어하도록 해
준다.
361
아이폰과 맥 OS X 개발을 위한 오브젝티브-C 2.0
만일 스크립트 언어 사용자였다면 오브젝티브-C가 사용하는 여러 방법들이 구식으로 보일 수
있다. 90년대에 나온 스크립트 언어와 비교하면 오브젝티브-C는 80년대 언어이다. 내부에 빌트
인 된 정규 표현식 기능도 없기 때문에 문자열 처리도 고통스럽다. printf() 스타일의 형식으
로 문자열을 만드는 것은 처음에는 적응이 안 되겠지만 코코아를 알아가면서 익숙해질 것이다.
오브젝티브-C가 가비지 컬렉션을 가지고 있다고 해도 인터넷에서 얻은 예제 소스는 대부분 메
모리를 retain과 release를 사용해서 수동으로 사용하고 있을 것이다. 컴파일과 링크 단계를
거치는 개발은 코드 변경을 적용하고 결과를 보는데, 스크립트 언어에 비하면 한참 느리다. 정
수, 문자 배열, 문자열 객체 같은 타입도 수동으로 구별해 줘야 한다. 아울러 오브젝티브-C와 같
이 따라오는 C의 특성(포인터, 비트 연산, 자주 발생하는 메모리 에러 등)도 알아야한다.
과연 이런 고통을 감내하고도 오브젝티브-C를 굳이 사용해야 하는 것일까? 우선 성능이 오브젝
트-C를 사용해야 하는 한 가지 이유가 될 수 있다. 애플리케이션의 종류에 따라 오브젝티브-C
는 스크립트 언어보다 빠른 성능을 보여준다. 두 번째 이유는 코코아 인터페이스를 사용하기 위
해서이다. 대부분의 스크립트 언어는 Tk 툴킷(Tcl 언어를 위해 개발된)을 지원한다. 이 패키지도
동작 가능하지만 코코아가 제공하는 것과 같이 다양하고 멋진 사용자 인터페이스는 가지고 있지
않다. 그리고 중요한 점은 Tk로 빌드된 응용프로그램은 맥 프로그램이 가지고 있는 룩앤필
(Look&Feel)을 가지고 있지 않다는 것이다.
여러분은 스크립트 브릿지를 사용해서 이 두 언어의 장점을 모두 가질 수 있다. PyObjC라고 하
는 오브젝티브-C와 파이선을 위한 브릿지와 RubyObjC라고 하는 오브젝티브-C와 Ruby를 위
한 브릿지가 있으므로 이런 스크립트 언어 모두에서 오브젝티브-C의 기능을 사용할 수 있다. 이
런 브릿지를 사용하여 파이선이나 루비에서 코코아 객체를 서브클래싱할 수 있고 코코아의 기능
에 접근할 수도 있다.
요약
오브젝티브-C와 코코아는 다른 프로그래밍 언어와 툴킷과는 다르다. 오브젝티브-C는 깔끔한
기능과 동작 런타임 디스패치에서 온 기능을 가지고 있다. 여러분은 오브젝티브-C를 이용해서
다른 언어에서 할 수 없었던 작업을 할 수 있는 것이다.
오브젝티브-C는 수년간에 걸쳐 다른 언어에 추가된 훌륭한 기능 몇 가지를 가지고 있지 않다.
특히 강력한 문자열 처리, 네임 스페이스, 메타 프로그래밍 등은 오브젝티브-C가 가지고 있지
않은 다른 언어의 특징이다.
362
부록. 다른 언어에서 오브젝트 C로
프로그래밍에서는 모든 것이 비교와 선택을 요구한다. 여러분이 지금 사용하고 있는 언어에 비
해서 오브젝티브-C를 선택할 가치가 있는지를 확인해서 득과 실을 따져보자. 여러분은 오브젝
티브-C에 익숙해지는 데 투자한 노력과 시간 이상의 보상으로써, 코코아를 사용해 멋진 애플리
케이션을 만들 수 있게 될 것이다.
363