Swift 익스텐션, Obj-C 카테고리 메서드명 Prefix하기

Obj-C category의 위험성

Obj-C에서 동일한 메서드 이름을 가진 카테고리(category) A, B가 동시에 존재하더라도, 컴파일 타임에 오류가 발생하지 않고 정상적으로 빌드되어 실행이 가능하다. 하지만 런타임에서 A와 B중 어떤 녀석이 먼저 호출될지 알 수 없기때문에 (규칙이 없으며 랜덤하게 호출됨) 매우 위험한 상황이 발생한다. 이를 방지하기 위해서 Obj-C에서 카테고리 메서드에는 프로젝트에서 사용하는 고유의 prefix를 붙여줘서 이름이 완전히 겹칠 확률을 최대한 줄여주는 방식을 꼭 사용해야 한다. 그렇지 않으면 외부 라이브러리를 사용할때 해당 라이브러리에 동일한 category명이 존재해서 랜덤하게 호출되는 상황이 발생 할 수 있다. 이는 매우 원인 파악도 힘든 에러가 될 것이기에 꼭 피해야 한다.

  • 문제상황) UIImage+MyProject.hUIImage+ExternalProject.h가 동시에 import되어있는 상황에서 [UIImage from:]을 호출하는 경우 누가 불릴지 아무도 장담할 수 없다.

  • 해결) category method에 prefix를 붙여준다

Swift extension은 어떨까?

그렇다면 Swift extension을 정의할때도 Obj-C에서 처럼 메서드 이름을 지을때 주의를 해야할지 알아보도록 하자.

Swift의 경우 Obj-C와 달리 module개념이 생겼기때문에 같은 Swift module내에 존재하는 extension에 동일한 메서드 이름 가진 메서드가 존재할 경우 바로 컴파일 에러가 발생한다.

하지만 여전히 Obj-C 코드와 섞이는 경우 무엇인가 불안하다. 아래와같이 완전히 동일한 메서드 명을가진 swift extension과 obj-c category를 각각 같은 프로젝트에서 컴파일을 진행할때는 어떻게 될까? 혹시나 문제가 없을지 궁금해서 일부러 동일한 메서드명을 갖도록 만들어서 실험을 해 보았다. (앞에서 언급했듯이 실제로는 Obj-C 카테고리를 메서드를 정의할때는 꼭 prefix없이 만드는 것이 좋다.)

  • Swift version

  • Obj-C version

두 함수가 모두 정의된 채로 컴파일 되었을때

메서드 이름이 완전히 동일함에도 불구하고 컴파일 에러는 나지 않았다. Obj-C의 category와 이름이 겹치는 것은 컴파일러에서 잡아주지 못하는듯 하다.

런타임에서는 아래와같이 약간 신기하게 동작한다.
1. Swift에서 UIImage.from(UIColor.clear)를 호출시 swift version의 함수가 호출됨
2. Obj-C에서 [UIImage from:[UIColor clearColor]] 호출시 Obj-C version의 함수가 호출됨

둘 중 어느 한쪽만 정의된 채로 컴파일 되었을때

여전히 문제 없이 잘 컴파일 되며 Swift에서 호출하던, Obj-C에서 호출하던 유일하게 정의된 해당 메서드가 문제없이 호출된다. (Obj-C category/Swift extension 둘다 동일하게 동작)

결론

Swift extension을 작성할때는 prefix를 붙일 걱정을 할 필요가 없다. Swift간에는 컴파일러가 알아서 에러를 뱉어줄 것이고, Obj-C의 category에만 잘 prefix가 붙어있다면 Swift와 Obj-C사이에 이름이 겹칠 가능성은 없기 때문이다.

  • Dongjin Suh

    안녕하세요~ 저의 경우는
    Xcode9에서 Swift3 @objc Interface 설정을 Default인 상태에서 테스트해봤는데(기본 설정),
    위 샘플 코드에서 Swift extension method 선언에 @objc를 넣으면 Swift extension/Obj-C 카테고리 메소드가 모두 정의된 채로 컴파일시켰을 때,
    Swift extension쪽에서 컴파일 에러가 발생하는 것을 확인했습니다.