iOS & Swift

Objective-C 대괄호 문법, 왜 이렇게 생겼을까? (메시지 전송의 비밀)

iOS 공부를 시작하고 처음 Objective-C 코드를 보면 당황하기 쉬워요.

이석우iOS Developer5분 읽기
Objective-C 대괄호 문법, 왜 이렇게 생겼을까? (메시지 전송의 비밀) 대표 이미지

iOS 공부를 시작하고 처음 Objective-C 코드를 보면 당황하기 쉬워요.

온통 대괄호 [ ] 투성이거든요. 함수 호출인 것 같긴 한데, 다른 언어랑 생김새가 너무 다르니까요.

“이걸 왜 이렇게 만들었지?” 하는 궁금증이 남기 마련이에요.

결론부터 말씀드리면, Objective-C의 대괄호는 함수를 “호출”하는 게 아니라 객체에게 “메시지를 보내는” 문법이에요. 이 개념 하나만 잡으면 낯설던 대괄호가 갑자기 눈에 들어와요.

오늘은 이 대괄호가 왜 이렇게 생겼는지, 그 뿌리부터 편하게 풀어볼게요. 😊

Objective-C 대괄호 문법, 이 생김새엔 다 이유가 있습니다
Objective-C 대괄호 문법, 이 생김새엔 다 이유가 있습니다

핵심 요약부터 짚고 갈게요

먼저 이 글에서 얻어가실 내용을 정리했어요.

  1. Objective-C 대괄호는 “객체에게 메시지를 보낸다”는 뜻이에요
  2. 이 문법은 Smalltalk라는 언어에서 물려받았어요
  3. [객체 메서드] 구조 하나만 알면 대부분 읽혀요
  4. 내부적으로는 objc_msgSend라는 함수로 바뀌어 실행돼요

이 네 가지만 이해하셔도 오늘 목표는 다 이룬 거예요.


Objective-C 메시지 전송 문법, 대체 뭔가요?

보통 다른 언어에서 메서드를 부를 땐 이렇게 쓰죠.

object.method()

그런데 Objective-C는 이렇게 씁니다.

// dog 객체에게 bark 라는 메시지를 보낸다
[dog bark];

// count 값을 인자로 함께 보낸다
[dog barkTimes:3];

생김새는 낯설지만 구조는 단순해요.

[받는객체 보낼메시지]

대괄호를 열고 왼쪽에 메시지를 받을 객체를 두고 오른쪽에 보낼 메시지를 적어요.

그래서 [dog bark]는 “dog야, bark 해줘”라는 뜻이 됩니다.

저는 이걸 “함수 호출”이 아니라 “말 걸기”라고 이해하니까 훨씬 편하더라고요.

인자가 여러 개일 땐 이런 식으로 늘어나요.

// 메시지 이름이 setName:age: 두 조각으로 나뉜다
[person setName:@"철수" age:20];

콜론(:)마다 값이 하나씩 붙는다고 보시면 됩니다.


대괄호는 왜 이렇게 생겼을까?

Objective-C의 대괄호는 Smalltalk라는 언어의 “메시지 전송” 철학을 C 언어 위에 얹으면서 생긴 흔적이에요.

이야기는 1980년대 초로 거슬러 올라가요.

브래드 콕스(Brad Cox)와 톰 러브(Tom Love)라는 두 사람이 Objective-C를 만들었어요.

이들은 당시 유행하던 C 언어를 그대로 쓰되, 여기에 객체지향 개념을 더하고 싶었어요.

그 객체지향의 롤모델이 바로 Smalltalk였습니다.

Smalltalk의 핵심 철학은 “모든 것은 객체이고, 객체끼리는 메시지를 주고받는다”는 거였어요.

문제는 C의 문법을 망가뜨리지 않으면서 이 메시지 개념을 넣어야 했다는 점이에요.

그래서 C 문법에서 거의 안 쓰이던 대괄호를 가져다가, 이 안을 메시지를 보내는 공간으로 정한 거예요.

덕분에 기존 C 코드와 섞여도 충돌 없이 구분이 됐죠.

메시지를 '보낸다'는 감각이 익으면 대괄호가 편해져요
메시지를 '보낸다'는 감각이 익으면 대괄호가 편해져요

이 언어는 이후 NeXT라는 회사가 채택했고, 애플이 1996년 NeXT를 인수하면서 맥과 아이폰 개발의 뼈대가 됐어요.

우리가 아는 Cocoa 프레임워크도 여기서 나왔고요.

낯선 대괄호 하나에 이렇게 긴 역사가 담겨 있는 셈이에요.


점(.) 문법이랑 뭐가 다를까?

요즘 Objective-C 코드를 보면 점(.) 문법도 자주 보여요.

dog.name 처럼요.

그래서 헷갈리기 쉬운데, 둘의 관계를 표로 정리해봤어요.

구분 대괄호 문법 점(.) 문법
형태 [dog name] dog.name
의미 메시지 전송 프로퍼티 접근
등장 시기 초창기부터 Objective-C 2.0(2007년) 이후
내부 동작 메서드 실행 사실상 메서드로 변환

재밌는 건, 점 문법도 결국 내부에서는 대괄호 메시지로 바뀐다는 점이에요.

dog.name은 실행될 때 [dog name]과 같은 일을 하는 거죠.

점 문법은 그저 보기 편하게 만든 겉옷 같은 거예요.

그래서 저는 초보자분들께 본질은 대괄호라고 먼저 이해하시길 권해요.


대괄호 안에서 실제로 무슨 일이 벌어질까?

조금 더 깊이 들어가 볼게요.

[dog bark]라고 쓰면, 컴파일러는 이걸 objc_msgSend라는 함수 호출로 바꿔요.

// 우리가 쓴 코드
[dog bark];

// 내부적으로는 대략 이렇게 변환된다
objc_msgSend(dog, @selector(bark));

첫 번째 자리에 메시지를 받을 객체, 두 번째 자리에 실행할 메서드의 이름표(셀렉터)가 들어가요.

겉모습은 달라도 결국 한곳으로 모여요
겉모습은 달라도 결국 한곳으로 모여요

이 방식은 어떤 메서드를 실행할지 실행 시점에 결정해서 유연해요.

덕분에 Objective-C는 실행 도중에 메서드를 바꾸거나 추가하는 동적인 기능이 강했어요.

대괄호라는 겉모습 뒤에 이런 유연한 구조가 숨어 있던 거죠.

며칠 쓰다 보면 손에 붙는 문법이에요
며칠 쓰다 보면 손에 붙는 문법이에요

Q&A로 정리해볼게요

Q. 대괄호를 꼭 외워야 하나요?

외운다기보다 [받는객체 보낼메시지] 구조 하나만 감을 잡으면 자연스럽게 읽혀요.

Q. 지금은 Swift 쓰는데 알아야 할까요?

오래된 라이브러리나 예제 코드가 여전히 Objective-C로 되어 있어서, 읽을 줄 알면 큰 도움이 돼요.

Q. 대괄호 안에 대괄호가 또 있으면요?

안쪽 결과를 바깥이 다시 받는 구조예요. 안에서 밖으로 읽으면 풀립니다.


대괄호가 그저 이상한 규칙처럼 보이다가도, “객체에게 말을 거는 문법”이라고 생각을 바꾸면 훨씬 친근해져요.

낯선 문법일수록 그 뿌리를 알면 오히려 오래 기억에 남더라고요.

오늘 이 글이 Objective-C와 조금 더 친해지는 계기가 되면 좋겠어요. 응원할게요! 🙌

함께 보면 좋은 글