Objective-C

1 개요

C 언어에서 파생된 객체 지향 프로그래밍 언어. 오브젝트시(Object-C)라고 아는 사람이 많은데, '오브젝티브시'다. 국내 한정으로 보통 줄여서 옵씨, 오브젝씨라고 부르며, 이 문서도 해당 항목으로 들어올 수 있다.

2 역사

1983년에 브래드 콕스와 톰 러브가 '스몰토크(Smalltalk)의 문법을 C에서 사용할 수 없을까?'라는 생각을 하다가 만들었다. 당시 애플에서 쫓겨나 넥스트 사를 차린 스티브 잡스의 눈에 띄어 그 이후로는 주구장창 애플의 표준 프로그래밍 언어로 사용되고 있다. 넥스트가 아예 이 언어의 모든 권리를 구매해버렸고, 이건 고스란히 애플에게 넘어간 것. 지금도 Objective-C 언어의 표준화와 스펙 관리를 책임지는 주체가 애플이다(그래서 표준 파운데이션 프레임워크를 보면 넥스트의 흔적이 많이 남아있다. NSDictionary, NSString의 접두어인 NS는 모두 넥스트의 운영체제였던 넥스트스텝(NeXTSTEP)의 준말).

3 특징

3.1 C의 확장

안시(ANSI)무냐 C 언어에 무형성(untyped) 순수 객체 지향 언어인 스몰토크 형식의 객체 지향 패러다임을 확장 형태로 얹은 언어로[1], 실제로는 C 언어라고 봐도 무방하다[2]. 그러나, C의 기본 자료형 및 표준 라이브러리에서 제공하는 것의 상당수를 Objective-C의 객체나 코코아 등에서 보다 손쉽게 사용할 수 있는 형태로 대체하고 있기 때문에, 실제 코드에 순수 C 부분은 많이 보이지 않는 편이다. 즉, 모든 C 코드가 다 문제 없이 작동하긴 하지만[3], C의 확장이라기보다 C에 Objective-C라는 새로운 언어를 덮어씌운 것에 가깝다.

C로 작성된 프로그램이 별도의 추가 런타임 없이 동작하는 것에 반해, Objective-C는 C 언어에 객체 지원을 추가했기 때문에 별도의 런타임이 필요하다. 하지만 그렇다고 JVM같은 가상 머신 위에서 동작하는 것은 아니고, 그저 객체간의 통신('메시징'이라고 부른다.)을 지원하는 초소형의 라이브러리를 링크하는 것이다[4].

3.2 C++과의 비교

C의 확장이면서 여러가지 기능을 추가했다는 측면에서 C++와 자주 비교되는 경우가 많은데, 사실 두 언어는 발전의 방향이 다르다. C++는 Objective-C에 비하면 훨씬 육중한 언어로, 지원하는 기능도 많다. 실행 시간에 거의 모든 것을 수행하도록 설계된 Objective-C와는 달리 C++은 성능을 위해 대부분을 컴파일 시간에 처리하도록 되어있어 실행 시간의 스루풋 역시 C++ 쪽이 월등하다. 다만 그런 만큼 배우기도 힘들고, 배워서 그 모든 기능을 제대로 사용하기는 훨씬 더 힘들며[5], 무엇보다 저 기능을 제대로 다 지원해주는 컴파일러가 없다[6]. 더 큰 문제는, 설정해놓은 기능이 워낙 많다 보니 컴파일러마다 지원하는 C++의 기능들이 다소 차이가 나기 때문에 C++가 모토로 내세우는 '하나의 코드로 모든 플랫폼에서 컴파일 가능(Write once, compile everywhere)'도 좀 무색한 상황. Objective-C는 거기에 비하면 훨씬 심플한 언어이기 때문에 그런 경우는 거의 없다고 볼 수 있다……지만, 어차피 거의 애플 기기에서 밖에 안 쓴다. 또한, 비록 C++가 C에서 파생됐다고 해도, 이미 C라고 부르기엔 너무 진화해버린 언어[7]인데 반해, Objective-C는 그냥 C 언어 위에 객체 지향 등의 확장을 추가한 수준이다. 즉, Objective-C는 곧 C라고 할 수 있다.

Objective-C의 내부로 조금 더 깊게 들어가자면, Objective-C의 모든 객체는 사실 C의 구조체(struct)로 이루어지고, 객체의 메서드는 해당 메서드 구현체(==함수)로의 함수 포인터를 클래스 객체[8]의 구조체 안에 리스트 형태로 들고 있다. 객체의 메서드를 호출하면 런타임의 objc_msgSend라는 함수를 통해 정확한 메서드 구현체를 찾아 호출한 후 결과를 돌려주는 형식이다[9]. 때문에 objc_msgSend 함수는 극도로 짧고 빠른 동작이 보장될 필요가 있어서 어셈블리 레벨에서 사람의 손으로 직접 작성됐다. 인터넷에서 만날 수 있는 몇몇 구루들이 분석한 바에 따르면, 최악의 상황에서도 대략 열몇 번의 CPU 사이클이면 정확하게 대상 메서드를 찾아온다고 한다[10]. 물론, 설계자들도 이 방식이 매우 느리다는 것을 알고 있었고, 그것 때문에 메서드 캐싱 기능[11]을 초창기부터 지원했다. 뭐, 그렇다고 해도 이 속도 문제 때문에 OS X을 겨냥하고 만들어진 프로그램도 퍼포먼스가 중요한 경우[12]에는 Objective-C보다는 C++로 작성하는 경우가 있다[13].

애플은 저 런타임의 소스 코드를 오픈 소스로 공개했다. 따라서, 런타임과 Objective-C 지원 컴파일러만 있다면 OS X이 아닌 다른 플랫폼에서도 Objective-C를 사용할 수 있다[14]. 그래서 만들어진 것이 GNU의 그누스텝(GNUSTEP). 사실상 Objective-C를 맥 전용으로 강제하던 코코아 프레임워크를 자체적으로 다시 작성해 다른 플랫폼에서 사용이 가능하도록 했다[15]. 이것 말고도, 개인이 코코아 프레임워크를 처음부터 다시 작성하는 프로젝트를 진행 중이기도 하다.

3.3 문법

Objective-C의 문법은 프로그래머마다 호불호가 크게 갈리는 편인데, 메서드 매개 변수마다 어떤 용도인지 이름을 붙여주고 단순 블록만이 아닌 여러 가지 기호를 이용하여 구분하는데다가, 저런 '독특한' 문법이 해당 언어의 직계 선조인 순수 C와 명료하게 구분이 되는 편이기 때문에 읽기 쉬운 문법이라며 찬양하는 사람도 있는 반면, C와 100% 호환이 되지는 않지만 문법을 거의 다 C 스타일로 녹여낸 C++/자바/C\# 등의 대부분의 메이저 언어들과는 다른 길을 걷고 있기에 눈에 거슬린다며 비판하는 사람들도 많다.

아이러니하게도, Objective-C 찬양론자들은 Objective-C 의 가장 강력한 부분을 바로 저 이상한 문법에서 찾는다. 특히 메소드 호출시 각각의 인자에 레이블을 붙여 이용하는 부분이 예시로 많이 등장하는데, 여러개의 인자를 받는 함수의 경우, 일반적인 C 계열 언어에서는 각각 인자가 어떤 역할을 하는지 함수명만 봐서는 알수가 없기때문에 각각 인자의 위치와 순서를 따로 외우던가 아니면 코멘트를 써줘야 하지만, Objective-C 에서는 메소드명 자체가 저런 코멘트의 역할을 대신할 수 있다. 예를들어, (x, y) 좌표와 Width, Height 를 받아서 사각형을 그리는 메소드의 경우 Objective-C 에서는 drawSquarePosX:PosY:Width:Height: 같은 함수명을 사용할 수 있고, 실제 사용시에는

[self drawSquarePosX:130 PosY:70 Width:100 Height:150];

처럼 되기때문에, 메시징하는 줄만 보고서도 그게 어떤 명령인지 대략적인 파악이 가능하다. 또한, 저 레이블 자체가 메소드명에 포함되기때문에 Width 와 Height 대신 또다른 (x, y) 좌표를 받아서 사각형을 그릴 경우에도 네이밍 컨플릭트 없이 drawSquarePosX:PosY:PosX:PosY: 등과 같은 메소드를 정의할 수 있다. 물론, 이런 방식은 메소드명 자체가 무지막지하게 길어지는 부작용을 갖고있지만, Objective-C 의 용도상, XCode 가 아닌 일반 에디터를 사용해서 코딩하는 경우가 별로 없기때문에 큰 문제로 생각되는 경우는 별로 없는듯.

4 여담

앱 스토어가 선풍적인 인기를 끌게 되면서 Objective-C를 배워서 앱을 출시하려는 일반인들이 많아졌으나, Objective-C는 생각보다 배우기 쉬운 언어는 아니기 때문에[16], 중도하차하는 사람들이 많은 편이다. 사실, C 언어와 객체 지향 프로그래밍, GUI 프로그래밍에 대한 경험이 없다면, 꽤 고전할 가능성이 높다.

초창기 컴파일러를 만들 때, 넥스트에서 GCC 소스를 몰래 가져다가 자신들만의 Objective-C 컴파일러를 만들었었다. 그러다가 GNU에게 딱 걸려서, 결국 넥스트가 GCC를 기반으로 구현한 Objective-C 컴파일러와 기타 추가 기능을 다시 GCC에게 돌려주는 형태로 합의를 봤다고. 이후 애플은 LLVM이라는 새로운 개념의 컴파일러 프로젝트를 통채로 인수했다.[17] 대학원 프로젝트로 시작된 것인데, 이 프로젝트를 처음 시작한 사람(크리스 래트너; Chris Lattner(위키백과에 따르면 아래에 나오는 Swift를 만들었다고 나와있다.))을 애플이 스카우트했다. 물론 프로젝트는 여전히 오픈 소스다. [18]

위에서 언급했듯, 애플의 거의 모든 제품은 Objective-C 기반이기 때문에, OS X이나 iOS용 프로그램을 작성하려면 필수적으로 익혀야 한다. 게다가 개발용 IDE인 Xcode가 맥에만 출시됐기 때문에[19], 일단 맥부터 사야 한다. 그리고 슬슬 애플빠가 되어가겠지.

5 위기

dev_01-1.jpg
WWDC 2014에서 새로운 프로그래밍 언어인 Swift가 발표되었다. 더 간단한 표현, 스크립트 언어와 같은 실시간 코드 실행 등의 강력한 성능을 갖추고 Obj-C의 뒤를 잇는 애플의 차세대 프로그래밍 언어로 자리매김 할 것이라는 팀 쿡과 크레이그 페더리히의 선언 하에 앞으로는 Swift를 중심으로 개발자 지원이 이루어질 것으로 보인다. Obj-C는 앞으로도 레거시 프로그래밍 언어로 계속 지원이 될 수 있고 심지어 기존 Obj-C 코드 사이에 Swift 코드를 섞어 쓸 수도 있는 등 아직까지는 여러가지 배려가 이루어지는 상황이지만 애플의 레거시 배려에 안주하다가는 어떤 꼴이 나는지는 Carbon이 64비트 시대에 어떻게 토사구팽을 당했는지, 로제타 VM이 얼마나 신속하게 퇴출되었는지, Cocoa에서의 Java 지원이 지금 어떤 꼴인지를 생각하면 뻔한 일이다. 애플은 게으른 개발사, 개발자를 다독이는 곳이 아닌지라 서드파티 입장에서는 빠르게 발 맞춰 전환하는 일 밖에 없을 듯 하다.

BpJXGeiIMAAP7If.jpg
이미 이런 사진이 흥하는 중.(....)
C와 C++ 문법에 익숙해진 모든 프로그래머들이 환호한건 덤

레거시 지원에 대한 악명으로 유명한 애플이지만, Objective-C는 여타 버려진 레거시와 태생 자체가 다르다.
OS X, iOS을 포함하여 이들의 조상격인 NeXTSTEP 그리고 이 OS 플랫폼들 위에서의 프레임워크인 Cocoa/Cococa touch 등 Apple의 다양한 기술들이 Objective-C 언어를 주 기반으로 작성되어 있기 때문이다. 그렇다. Objective-C는 Apple과 실로 역사를 함께한 것이다.
그리고 앱스토어의 역사와 함께한 수많은 누적된 iOS/OS X 어플리케이션들의 유지보수 / iOS, OS X 앱이 사용하는 C++ 서드파티 라이브러리 / 더 깊은곳을 볼 수 있는 디버깅(+ Assembly) 등을 위해서
진정한 OS X / iOS 개발자가 되기 위해서는 Objective-C는 결국 피할 수 없는 산이라고 보는 해외 양덕횽들의 의견들이 주를 이루는 것으로 보인다.
결론은 둘 다 배워야!.....

6 Cocoa 기반 언어

스위프트나 Objective-C나 결국 Cocoa 프레임워크 기반 위에서 작성되기 때문에 소스코드를 놓고 살펴보면 클래스명, 메소드 명등 그리 큰 차이가 없으며 당연히 앱 라이프사이클 등에 대한 메서드 또한 동일하다.

Objective-C를 Swift로 포팅작업을 할때 보면 이건 마치 한국어를 일본어로 번역하는 기분으로 작업이 가능하다. 일본어를 모르면?
  1. Objective-C와 스몰토크는 서로 사용하는 특수문자가 매우 다르기 때문에 문법이 비슷하다고 보기는 힘들다.
  2. 초창기 Objective-C 컴파일러는 Objective-C 코드를 일단 순수 C 코드로 번역한 후, 이것을 컴파일해 바이너리 결과를 뱉는 형태로 구현됐다. 물론 지금은 Objective-C 코드에서 바로 바이너리로 직행한다. C++ 컴파일러의 발전사를 그대로 따라갔다. 물론, 바이너리로 바로 변환하는 것보다 C로 변환한 후, C 컴파일러가 바이너리를 만들게 하는 쪽이 훨씬 쉽기 때문에, Objective-C나 C++뿐 아니라 상당수 언어가 초기에는 C 코드로 변환하는 식으로 개발되고, 나중에 인기를 얻고 퍼포먼스가 중요해지면 그 때 가서 직접 바이너리를 만드는 식으로 개선된다.
  3. 지금은 사라진, 애플의 공식 언어 명세서 'Objective-C 프로그래밍 언어(The Objective-C Programming Language)'에서는 'A valid C code is also a valid Objective-C code'라고 서술했었다. 즉, Objective-C 소스 코드 파일(*.m) 내에서는 'C 코드 == Objective-C 코드'라는 것.
  4. OS X은 libobjc.A.dylib, Windows는 objc.dll.
  5. C++의 창시자인 비야르네 스트로스트럽(Bjarne stroustrup)도 C++이 지나치게 전문가 전용 언어가 되었다고 비판하였다. 현재 C++ 표준은 ISO 위원회에서 정하는데, 이 위원회 인물들이 개발자라기보다는 (이론에 충실한) 전문가에 가깝기 때문에 그렇게 된 것 같다고.
  6. LLVM과 클랭(Clang)이 아예 주춧돌부터 C++로 작성된 만큼 C++11을 가장 표준에 근접하게 지원한다. 반면 GCC는 요즘 C 기반 소스 코드를 몽땅 C++로 재작성하느라 정신이 없다. 사실 GCC는 어지간하면 표준에 근접하게 만들기보다는 GCC 확장이라는 자신들만의 표준을 만들어서 사용한다. 물론 GCC가 워낙 사용자 베이스가 많아서 이 확장이 데 팍토(de facto)가 된다는 게 문제 아닌 문제.
  7. C와의 호환성이 높은 편이긴 하지만, 객체 지향 프로그래밍뿐만 아니라 일반화 프로그래밍 및 여러가지 다른 프로그래밍 패러다임 대부분을 탑재하여 뷔페식 언어가 되었다.
  8. 이 또한 Objective-C의 특징으로, 우리가 흔히 설계도라고 생각하는 클래스 그 자체도 객체로 존재하며, 당연히 클래스 메서드라는 것도 존재한다. 이 클래스 객체는 또 그들끼리의 상속 관계가 있어, 클래스 객체의 수퍼 클래스는 메타 객체라는 통괄 객체로 이어져있다.
  9. 더 정확하게 말하자면, 모든 메서드 호출(==메시지 전송)이 컴파일 시간에 저 objc_msgSend 함수 호출로 치환된다.
  10. 하지만, C++는 메서드 호출이 CPU 한 사이클(점프 명령)로 이루어진다. (물론 매개 변수 전달 등을 합치면 몇 사이클 더 필요하다.) 이것에 비하면 Objective-C의 메서드 호출에는 엄청난 시간이 소요되는 셈. 특히, 객체 지향 언어는 메서드 호출이 초당 수천 번 이상 이루어지는데, 얼마나 많은 명령어가 필요할 지 생각해보라. 이것이 바로 Objective-C를 비판하는 사람들의 주된 주장이다. 언어 자체가 지나치게 느리다는 것. 사실 퍼포먼스는 생산성에 반비례하는 경향이 있고, Objective-C의 생산성이 C++보다는 나은 편이기 때문에 그냥 언어 특성으로 볼 수도 있다.
  11. 아까 언급한 클래스 구조체에는 cache라는 해시 테이블이 들어있다. objc_msgSend는 일단 이 캐시 해시 테이블을 뒤진 후 나오는 게 없으면 그 때부터 저 긴 메서드 검색을 시작한다. 찾으면 메서드 이름(셀렉터; Selector)을 키 삼아 캐시에 저장하고, 못 찾으면 식별 불가능 셀렉터(unrecognized selector) 예외를 터트린다.
  12. 대부분의 경우는 게임이다. 사실, C++로 작성하는 편이 퍼포먼스뿐만 아니라, 포팅에도 유리하기 때문에 맥에서도 게임은 대부분 이런 식으로 만든다. 아니, 차라리 다른 플랫폼에서 C++로 만들어진 게임을 맥으로 포트하는 경우가 사실 더 많다.
  13. 물론 이렇게 하면 코코아를 사용할 수 없어 최신 시스템 API에 접근하지 못한다는 부작용이 있기 때문에, 그 절충안으로 내부 엔진은 C++로 작성하되 UI 부분만 Objective-C++를 사용하기도 한다.
  14. 그런데 문제는, 저 소스 코드가 완벽하게 범용성을 고려하고 작성하지 않아서, 다른 플랫폼에서 컴파일을 시도하면 특정 헤더 파일이 없다고 백이면 백 오류가 뜬다. 게다가 저 헤더 파일은 맥에만 있다! 컴파일 미, 이프 유 캔.
  15. 유닉스 플랫폼의 Étoilé 프로젝트가 바로 이 그누스텝을 적극적으로 이용한 데스크탑 환경이다.
  16. 이는 사실 교재 문제도 크다. 언어의 점유율이 급속도로 높아지긴 했으나, 가시권에 들어온지는 얼마 안 된 언어이기 때문에, 쓸 만한 교재가 매우 부족하다. BNR이 이쪽에서 바이블 취급을 받고 있지만 이것도 사실 타 언어의 좋은 교재들에 비하면 잘 짜여진 교재라고 보기는 힘들다. 현재로선 경쟁자들이 거의 없고 있는것도 워낙 허접해서 독보적인 위치를 차지하고 있을뿐.
  17. 대략 89년 쯤 얘기인데 잡스가 여전히 여기에 뒤끝이 남아서 GCC, Samba등을 맥에서 내칠려고 한다는 카더라가 있다. 굳이 그런게 아니더라도 GNU쪽 눈치보며 기술 공개하는게 애플같은 기업 입장에서 석연치 않은 것은 당연하다.
  18. 최신 버전의 Xcode에는 GCC가 아직 남아있긴 하다. 이는 LLVM이 직접적인 컴파일러 프론트엔드가 아닌, 컴파일 과정에서 개입하는 "중간 언어"의 프로젝트이기 때문이다. 실제로, 애플의 새 컴파일러셋은 클랭이라는 프론트엔드가 Objective-C 코드를 해석해 IR이라고 하는 LLVM만의 중간 언어로 번역한 후, 이것을 다시 LLVM의 백엔드가 바이너리로 옮기는 것이다. 이 클랭+LLVM 조합은 컴파일러 선택 메뉴에 '애플 LLVM'이라는 형식으로 존재하고, GCC+LLVM 조합은 'LLVM GCC'라는 형식으로 옵션에 올라 있다. 문제는, 저 클랭이 신생 해석기라서, 수십년간의 최적화가 쌓인 GCC에 비하면 생성된 바이너리의 최적화 수준이 떨어진다는 것. 대신 컴파일 속도는 10~20% 빠르다고 한다.
  19. 당연한 소리겠지만.