편의 API를 컴파일러 알림으로 안전하게 제거하기
Deprecating your own convenience API
핵심 요약
- 이전 iOS의 동작을 맞추려고 만든 편의 API에 `@available`을 적용하면, 배포 타깃이 올라갈 때 컴파일러가 사용 위치를 경고나 오류로 알려준다.
- `deprecated`와 `obsoleted`를 함께 지정하면 먼저 경고를 받고 이후 오류로 전환할 수 있어, 기존 코드를 단계적으로 정리할 수 있다.
- iOS 18에서는 텍스트만, iOS 26에서는 아이콘만 표시하는 `ToolbarLabelStyle`을 예로 들어 편의 래퍼의 제거 시점을 관리하는 방법을 설명한다.
도입
새 플랫폼 API를 이전 버전에서도 쓸 수 있도록 직접 구현하거나 래퍼를 두면, 지원 대상이 새 OS로 올라간 뒤 그 코드가 불필요해질 수 있다. 예시에서는 iOS 18의 텍스트형 툴바 버튼과 iOS 26의 아이콘형 버튼 차이를 `ToolbarLabelStyle`로 처리한다. 이런 편의 API의 사용 지점에 가용성 어노테이션을 붙여 제거 시점을 컴파일러에 알릴 수 있다.
상세 요약
이전 플랫폼용 코드의 수명
새 iOS 버전에서 제공하는 API를 이전 버전에서 사용할 수 없을 때, 직접 구현이나 스텁을 둬서 버전별 동작을 맞출 수 있다. 그러나 최소 지원 버전을 새 버전으로 올리면 이 코드는 더 이상 필요하지 않을 수 있다. 저자는 보통 최신 플랫폼 두 버전을 지원하지만, iOS 26과 iOS 18에서는 툴바 항목 표시 방식처럼 작은 차이도 있어 호환 코드를 추가했다고 설명한다.
예시에서는 iOS 26에서 툴바 버튼을 SF Symbols 같은 이미지로 표시하고, iOS 18에서는 텍스트 버튼으로 표시한다. ToolbarLabelStyle은 #available(iOS 26, *)로 플랫폼 가용성을 확인하고, 새 버전에서는 .iconOnly, 이전 버전에서는 .titleOnly를 적용한다. LabelStyle 확장에 .toolbar 정적 프로퍼티를 추가해 뷰에 .labelStyle(.toolbar)로 적용한다.
가용성 어노테이션으로 사용 추적
편의 API를 만들 당시에는 자연스러운 코드처럼 보여도, 최소 지원 버전이 올라간 뒤에는 사용처를 찾아 제거해야 한다. 저자는 ToolbarLabelStyle 타입 자체가 아니라 .toolbar 프로퍼티에 가용성 어노테이션을 붙여 컴파일러가 사용을 추적하게 한다.
@available(iOS, deprecated: 26, obsoleted: 27,
message: "You don't need .toolbar anymore")
static var toolbar: Self { .init() }
deprecated: 26은 iOS 26을 대상으로 할 때 해당 프로퍼티 사용에 경고를 내게 한다. obsoleted: 27은 iOS 27 타깃에서 사용을 오류로 만든다. 오류로 바뀌기 전에 경고를 확인하고 사용처를 정리할 수 있다.
경고에서 오류로 단계적 전환
deprecated 없이 obsoleted: 26만 지정하면 iOS 26 타깃에서 바로 컴파일 오류가 발생한다. 저자는 이 방식이 작업을 막을 수 있으므로 먼저 deprecated로 지정하고, 이후 obsolete로 전환하라고 권한다. 컴파일러 경고를 쌓아 두지 않는 것도 중요하다.
이 방식은 이전 플랫폼을 위한 래퍼를 만들면서도 나중에 제거할 코드를 분명하게 표시한다. 이전 버전에서 새 SwiftUI API를 제공하는 백포팅 사례는 배포 타깃을 올리지 않고 SwiftUI API 백포팅하기에서 확인할 수 있다.
결론
편의 API에 `deprecated`와 `obsoleted`를 지정하면 지원 타깃을 올리는 과정에서 코드 정리 시점을 경고로 확인하고, 이후에는 오류로 강제할 수 있다. 곧바로 obsolete 처리하는 방법도 있지만 작업을 막을 수 있으므로 먼저 deprecated를 적용하는 편이 낫다고 글은 설명한다. 경고를 방치하지 않으면 오래된 래퍼가 코드베이스에 남는 일을 줄일 수 있다.