2014년 7월 21일 월요일

Swift 프로젝트에서 Objective-C 코드를 함께 사용하기

여러가지 이유가 있겠지만 두 가지 이상의 언어로 프로젝트를 진행하는 것도 종종 있다. 예를 들어 특정 언어로 작성된 써드파티 라이브러리를 가져다 쓴다거나 혹은 특수한 퍼포먼스 로직이 필요할 경우 등등이다. Xcode 에서는 스위프트(Swift) 프로젝트에서 C나 Objective-C 언어로 코딩된 파일을 함께 빌드하는 것이 가능하다.

이 글은 스위프트(Swift)를 주 언어로 설정한 프로젝트에서 Objective-C 코드를 함께 사용하는 방법을 기술한다. 반대로 Objective-C를 주 언어로 사용하는 프로젝트의 경우는 방법이 다르므로 관련글을 참고하자.

동일한 내용의 스크린캐스트

일단 특정 스위프트 프로젝트가 있다고 가정하자. Xcode 6 부터는 아래 스크린샷 처럼 프로젝트를 만들 때 사용하려는 주 언어를 설정하도록 되어 있으니 무슨 의미인지는 알 것이다.

복소수(complex) 예제가 아닌데 이름을 잘못 지었다! ;ㅁ;

이 프로젝트를 작업하는 도중 Objective-C 코드를 써야 할 일이 있다면? 그냥 평소에 하던대로 New File 메뉴를 이용해 Objective-C 클래스를 추가한다.


이렇게 Objective-C 클래스를 처음 추가하면 아래와 같이 브릿지 헤더를 만들겠냐고 물어온다.


이 브릿지 헤더는 스위프트와 Objective-C 코드를 같이 쓰기 위해서 꼭 필요하다. 따라서 당연히 YES를 선택 해야 한다. 그러면 프로젝트이름-Bridging-Header.h 라는 이름의 파일이 프로젝트에 추가된다.
참고: 위의 브릿지 헤더 추가 다이얼로그가 자동으로 안뜨는 경우가 있다. 버그라던가, 혹은 수동으로 파일을 프로젝트 디렉토리에 복사해 넣고 Add files를 하는 경우 등등의 경우는 뜨지 않았다. 이럴때는 그냥 수동으로 New File 메뉴를 이용해 C 헤더 파일을 동일한 방식의 이름을 지어서 프로젝트에 추가하자.
이름이 길어서 슬픈 파일이여... ;ㅁ;

애플에서는 이 브릿지 파일 이름을 'Projectname-Bridging-Header.h' 와 같은 식으로 짓는 것을 권장한다. 하지만 꼭 이렇게 지어야 할 필요는 없는 것 같다. 왜냐하면 빌드 세팅에서 이 브릿지 정의 헤더 경로와 파일 이름을 설정해 주어야 하기 때문이다.

위의 방식으로 브릿지 헤더가 자동으로 추가된 경우에는 아래와 같이 빌드 세팅(Build Settings)의 Objective-C Bridging Header 항목에 자동으로 해당 파일의 경로가 추가된다.


만약 브릿지 파일을 수동으로 프로젝트에 추가했다면 동일하게 빌드 세팅(Build Settings)에서 Objective-C Bridging Header 섹션에 브릿지 파일 경로를 추가해주자. 보통(?)이라면 $(SRCROOT)/ProjectName/ProjectName-Bridging-Header.h 와 같은 식으로 입력하면 된다.

이제 브릿지 파일을 편집하자. 자동으든 수동이든 추가한 브릿지 파일(ProjectName-Bridging-Header.h)을 열고 필요한 Objective-C 코드의 헤더 파일을 #import를 이용해 임포트시키는 코드를 작성한다.


사용하려는 Objective-C코드들의 헤더 파일을 임포트 하도록 브릿지 파일 편집이 끝났다면 이제 준비 작업이 끝난 것이다. 의외로 간단해서 참 싱겁다. 어쨌든, 이제 이 Objective-C 클래스나 함수들을 이용하면 된다.
참고: iOS나 OS X용의 일반적인 난이도(?)의 Objective-C 코드라면 여기까지만으로 매핑이 완료된다. 코드를 고치지 않고도 말이다. 물론 좀 고난이도(?)의 C함수 등등을 쓰는 코드가 있다면 Foundation에서 사용되는 타입을 사용하다록 코드를 수정해야 하는 수고가 필요할 수도 있다.
이번 글에서 사용하는 예제는 공백(Scratch)에서 시작한 예제라 Objective-C 코드가 비어있다. 일단 대충 아주 간단하게 Objective-C 파일을 코딩해봤다.


위 스크린샷은 그냥 예제이다. 보다싶이 생성자 하나와 메소드 하나가 있고 하는 일은 그냥 로그만 찍는 역활이다.

이제 이 코드를 스위프트 언어로 작성된 AppDelegate.swift 코드에서 실행시켜보자.


위의 예제처럼 그냥 스위프트로 만들어진 코드라고 생각하고 멋대로 코딩하니 의도한대로 잘 동작한다. 코코아 프로젝트라서 맥 데스크탑용 앱이 떴는데 iOS 프로젝트라도 별로 걱정할 것 없이 잘 될 것이다.

마무리

위의 예제는 너무 단순한 예제라서 완벽한 설명은 되지 못 한다. 예를 들어 함수나 메소드 호출 시 파라미터 규격을 어떻게 써야 하는가 등등 말이다.

하지만 걱정할 필요는 없다. 이미 Xcode 6 가 세 번째 베타를 맞이하면서 파운데이션(Foundation) 쪽의 데이터타입 클래스들은 이미 스위프트와 자동으로 호환되게 매핑이 되어있다. 예를 들어 NSArray 라던가 NSDictionary는 Objective-C 에서는 그대로 쓰면 되고 스위프트에서는 Array와 Dictionary 처럼 사용하던대로 쓰면 된다. 이미 CInt 같이 호환성을 위한 타입도 자동으로 어울리는 Int 타입에 매핑되는 듯 점점 스위프트와 Objective-C 혹은 C 파운데이션과의 호환성이 높아져 가고 있다.

다만 완전히 매핑되지 않은 프레임워크, 예를 들어 C API위주로 구성된 Carbon 등의 프레임워크는 완벽한 매핑이 되어있지 않아서 스위프트에서 호출하는게 여간 귀찮은 일이 아니다. 이럴 때는 오히려 위의 방법처럼 Objective-C 코드로 한번 더 감싸서(Wrapping) 쓰는게 더 편할 정도다. :-)

[관련글] Objective-C 코드의 Swift 별명 이야기 (Swift 3 기준)
[관련글] Objective-C 프로젝트에서 Swift 코드 사용하기
[관련글] Objective-C 제너릭(Generics)
[관련글] 스위프트(Swift) 가이드

댓글 2개 :

익명 :

좋은 정보 감사합니다 질문하나있는데 그럼 swift 에서 추가시킨 objc의 ui는 어떻게 처리해 주나요??

Renn Seo :

'objc의 ui' 라는 표현이 잘 이해가 안되네요. xib(nib) 라면 그건 objc로 만들어지는게 아니니 상관없습니다. 그리고 objc 인터페이스들은 전부 적절하게 swift로 번역되기 때문에 섞어 쓰더라도 큰 문제는 없을겁니다.