TIL: Objective-C 와 Swift 간 Property Type 호환 문제

Swift 가 발표된지 x년이 지났다. 지금까지 Objective-C (이하 ObjC) 를 사용하고 있던 회사들이 “이제 우리도 Swift 써볼까?” 라는 생각을 많이 할 것이다. 우리 회사도 같은 생각을 한 사람이 있었고 (…) 그 결과 현재 작업 환경은 ObjC 와 Swift 가 공존하는 형태가 되었다.

물론 기존 코드들을 ObjC 에서 Swift 로 변환할 수 있으면 참 좋겠지만, 현실적인 요소들로 인해 작업에 시간을 투자 할 수 없는 경우가 많을 것이다. 그래서 프로젝트 유지보수를 하다 보면 Swift 에서 만들어 진 모델을 ObjC 에서 써야 할 경우가 종종 생긴다.

하지만 이렇게 쓸때 마음대로 되지 않는 부분이 가끔씩 생기는데 그 중 하나가 바로 Property Type 이 서로 호환이 안되는 경우이다.

배경 : Bridge Header

Swift 로 작성된 코드를 ObjC 에서 접근하기 위해서는 Bridge Header 라는 파일이 필요하다. Swift 코드는 기본적으로 Header 파일이 없기 때문에 ObjC 에서 import 를 할 수 없기 때문이다.

이 파일은 Xcode 에서 ObjC 기반 프로젝트에서 개발자가 Swift 파일을 처음 생성할때 작성 여부를 묻는다. 만약에 잘못 클릭해서 생성되지 않았다면 <ProductModuleName>-Swift.h 이라는 파일을 직접 만들어줘도 무방하다.

#import "ProductModuleName-Swift.h"

Bridge Header 는 개발자가 Xcode 로 Swift 파일을 작성하는 동안 지속적으로 코드를 인덱싱 하면서 내용이 갱신된다. 이후에 Swift 파일 내에 있는 코드를 사용할 때 ObjC 파일 안에서 import를 해주면 된다.

문제 : 갱신이 안 된다?

나의 경우 Swift 로 만들어진 Model 을 ObjC 에서 사용하려고 할때 마주친 케이스다. Double형 Optional Property 를 ObjC 코드에서 사용하려고 하는데 자동 완성이 안되길래 잠깐 삽질을 하다가 Bridge Header 가 생신이 안되는 것을 발견했다.

class Item {
	var name: String
	var price: Double
	var sale: Double?

	init(name: String, price: Double) { ... }
}

이 상황에서 Item 객체의 sale 프로퍼티에 접근을 할 수 없는 상황이었다.

원인 : Objective-C 와 Optional Type

Swift 의 Optional Type 은 감싸고 있는 타입이 nil 값을 가질 수 있도록 해주는 기능이다. 아래 예제에서 보듯 Optional<T>를 줄여 쓴 것이 T?가 된 것이다. 엄밀히 말하자면 Optional 에도 여러가지가 있지만, 이 글에서는 Optional Type 만 언급한다.

let shortForm: Int? = Int("42")
let longForm: Optional<Int> = Int("42")

문제는 Swift 의 Optional Type 이 ObjC 에서 다루고 있는 Nullable과 차이가 있다는 것이다. 그래서 Xcode가 코드를 인덱싱 할 때 ObjC 와 호환되지 않는 것으로 판단하여 Bridge Header 에서 제외를 시켜 버리는 것이었다.

해결 : Default 값이 있는 Optional Type 으로 선언하자

아까 봤던 클래스 코드를 다시 보자. 문제가 됐던 Optional Type Property 를 어떻게 해결하면 될까? 바로 Optional Type Property 의 Default 값을 정해주면 된다. 수정한 예를 보자.

class Item {
	var name: String
	var price: Double
	var sale: Double? = 0.0

	init(name: String, price: Double) { ... }
}

Optional Type 의 기본값이라니 좀 이상할 수 있는데, Data Parsing 단계에서 nil 값을 넣을 수 있기 때문에 아주 의미 없지는 않겠다는 생각이 든다.

https://stackoverflow.com/questions/26366082/cannot-access-property-on-swift-type-from-objective-c

참고자료들

http://seorenn.blogspot.com/2014/07/swift-objective-c.html
https://developer.apple.com/swift/blog/?id=25
https://developer.apple.com/documentation/swift/optional
https://qiita.com/ylisr/items/6c8a93319e09565f9663