[[include(틀:작성중)]] [[TableOfContents]] ''오브젝티브 씨''라고 읽으면 된다. 애칭은 ''옵씨''. 브래드 콕스(Brad Cox)와 톰 러브(Tom Love)가 만든, '''20세기의 걸작 언어 Jr.'''라고 생각하면 당신은 멋쟁이. 안시(ANSI) [[C]]에 객체지향 층을 얹어 만들었다. 따라서 실행 시 반드시 런타임(libobjc.dylib 또는 objc.dll)의 도움을 받아야 작동 가능하다. 물론 런타임 라이브러리는 [http://opensource.apple.com/source/objc4/ 애플 오픈 소스 사이트]에 공개돼있으므로 '''능력이 있다면''' 얼마든지 정적 라이브러리로 만들어 붙여버려도 된다. == 역사 == 초기의 옵씨는 C에서 [[wiki:"OOP" 객체지향]]을 지원하도록 문법을 확장한, 일종의 문법적 편의사항(syntactic sugar)으로 구현됐다. 옵씨 컴파일러는 옵씨 코드를 읽어 C 코드를 뱉었고, C 컴파일러가 그걸 바이너리로 어셈블했다. 하지만 넥스트(NeXT Inc.)가 옵씨를 집어삼킨 이후, 옵씨 코드에서 바로 바이너리로 직행하는 컴파일러가 나왔다. 이를 위해, 예전에는 GCC를 이용했지만 요즘은 애플 주도의 [[LLVM/Clang]]을 이용해 컴파일한다. 물론 오픈 소스 LLVM/Clang 3와 Apple LLVM/Clang 4 모두 옵씨 코드를 컴파일할 수 있지만, 닫힌 가지인 Apple LLVM/Clang 4가 훨씬 월등한 어셈블 능력을 보여준다고. 애초에 버전부터 차이나니까. 여담으로 [[FreeBSD]] 재단에서 오픈 소스 LLVM/Clang 3를 다루던 사람이 [http://bsdtalk.blogspot.kr/2013/11/bsdtalk233-from-gcc-to-llvmclang-with.html 말하길], 참고삼아 [[GCC]] 4.2의 옵씨 담당 부분 소스 코드를 봤다가 기절할 뻔했다고. 무려 일만 줄이 넘어가는 '''단일''' C 파일 하나로 옵씨의 모든 걸 처리했단다. 이 GCC 확장에 대해서는 여러 루머가 있는데, 가장 유명한 걸 고려한다면 잡스가 빡쳐서 엿먹어라 하는 수준으로 GCC에 똥을 던진 듯. == 문법 == [[C]] 소스 코드는 곧 옵씨 소스 코드이다. 앞서 말했듯, 옵씨는 C에 확장을 얇게 바른 언어에 가깝다. 하지만 그렇다고 옵씨 소스 코드가 곧 C 소스 코드인 건 아니다. 이 단에서는 옵씨만의 고유한 문법과 기호에 대해 설명한다. === 클래스 선언 및 정의 === ==== 클래스 선언 ==== 클래스 선언은 외부로 노출 가능한 클래스 명세를 의미한다. 즉, 외부의 프로그래머들에게 '이 클래스는 이러이러한 기능을 가지고 있다'고 알리는 목적이다. 클래스 선언에 쓰이는 옵씨 고유의 문법은 {{{@interface}}} 명령과 {{{@end}}} 명령이다. {{{@interface}}} 명령은 선언하는 클래스의 이름과 상속하는 부모 클래스 이름, 그리고 쉼표로 구분된 준수할 프로토콜 이름의 목록을 인자로 받는다. 형식은 다음과 같다: {{{ @interface 클래스 이름 : 부모 클래스 이름 <준수할 프로토콜 이름 목록> }}} 여기서 부모 클래스 이름과 준수할 프로토콜 이름 목록은 선택적이다. 즉, 어떠한 클래스도 상속하지 않아 그 자신이 최상위 뿌리(root) 클래스가 될 수도 있고 어떠한 프로토콜도 준수하지 않을 수 있다. {{{@end}}} 명령은 {{{@interface}}} 명령의 영역을 닫는다. 아래에 몇 가지 예제가 있다: {{{ // 뿌리 클래스 @interface ParentClass1 @end // 뿌리 클래스를 상속한 클래스 @interface ChildClass1: ParentClass1 @end // 또 다른 뿌리 클래스이면서 동시에 Protocol1을 준수 @interface ParentClass2 @end // 또 다른 뿌리 클래스를 상속하면서 동시에 Protocol2와 Protocol3를 준수 @interface ChildClass2: ParentClass2 @end }}} 클래스 선언은 주로 헤더 파일에 넣는다. ==== 메서드 선언 ==== 메서드 선언 역시 선언의 일부이므로 클래스 선언 안에 들어간다. 메서드 선언문의 형식은 다음과 같다: {{{ // 클래스 메서드 선언문 + (반환형) 메서드 이름 ; // 인스턴스 메서드 선언문 - (반환형) 메서드 이름 ; }}} 선언문에서 `(반환형)` 부분은 생략 가능하다. 생략하면 기본 반환형인 `id`가 사용된다. 메서드 이름 부분은 다음과 같은 형식을 가진다: {{{ // 인자를 받지 않는 경우. 메서드이름 // 인자를 하나 받는 경우. // 이 경우, 메서드 이름은 '메서드이름과인자:'가 된다. 메서드이름과인자:(인자형)인자이름 // 인자를 두 개 받는 경우. // 이 경우, 메서드 이름은 '메서드이름과인자1:인자2:'가 된다. 메서드이름과인자1:(인자형)인자이름1 인자2:(인자형)인자이름2 // 인자를 세 개 받는 경우. // 이 경우, 메서드 이름은 '메서드이름과인자1:인자2:인자3:'이 된다. 메서드이름과인자1:(인자형)인자이름1 인자2:(인자형)인자이름2 인자3:(인자형)인자이름3 // 이 정도면 이해했겠지. }}} 시범삼아 메서드 몇 개를 선언해보겠다: {{{ // 클래스 메서드. 반환형은 char *. // 메서드 이름은 'iTakeNoParameter'. +(char *)iTakeNoParameter; // 클래스 메서드. 반환형은 id. // 메서드 이름은 'allocWithZone:'. // 하나의 인자를 받으며, 그 형은 NSZone *, 이름은 aZone. +allocWithZone:(NSZone *)aZone; +(id)allocWithZone:(NSZone *)aZone; // 같은 표현 // 인스턴스 메서드. 반환형은 NSInteger. // 메서드 이름은 'numberOfCharacter:inString:'. // 인자는 두 개를 받는다. 첫번째는 unichar형의 ch, 두번째는 NSString *형의 str. -(NSInteger)numberOfCharacter:(unichar)ch inString:(NSString *)str; // 인스턴스 메서드. 반환형은 없음. 메서드 이름은 'drawRectangleOfWidth:height:upperLeftX:upperLeftY:'. // 인자는 네 개를 받는다. 모든 인자는 CGFloat형이고 그 이름은 각각 w, h, x, y이다. -(void)drawRectangleOfWidth:(CGFloat)w height:(CGFloat)h upperLeftX:(CGFloat)x upperLeftY:(CGFloat)y; }}} 콜론 역시 메서드 이름의 일부임을 유의하자. 옵씨는 메서드 오버로딩을 지원하지 않는다. 따라서 중복된 이름의 메서드를 선언하면 컴파일 오류가 발생한다. 또한, 클래스 선언에 동봉된 모든 메서드는 공개(public) 가시성을 갖는다. 비공개(private) 메서드는 추후 설명하겠다. [[include(틀:ProgrammingLanguage)]]