Method Swizzling은 Selector와 뗄레야 뗄 수 없는, 실과 바늘 같은 그런 사이입니다. Method Swizzling이 Selector의 특징을 이용한 꼼수(?)이기 때문입니다. Selector에 대해서는 이전 글에서 설명한 적이 있습니다. 이 글에서 설명한 특징들 중 Selector는 런타임 시점에서야 실제 호출할 메서드를 결정할 수 있다는 특징을 이용해 기존 메소드 대신 원하는 메소드를 호출하도록 하는 것이 Method Swizzling 입니다.
Swizzling이 가능하려면 몇 가지 조건이 필요합니다.
1. Swizzling할 메소드는 @objc가 붙거나 Objective-C 런타임에 노출될 수 있어야 합니다.
2. message dispatch를 사용해야 하므로 메소드에 dynamic
키워드가 붙어야 합니다.(extension에서 정의될 경우 dynamic
이 붙지 않아도 message dispatch가 적용됩니다.)
이제 코드 작성을 통해 실제 동작을 설명해 보겠습니다.
Selector를 생성하고 class_getInstanceMethod
를 이용해서 메소드의 주소값을 받아옵니다. 이 주소값은 Optional로 제공이 되기 때문에 if let을 이용해 optional을 벗겨내어 method_exchangeImplementations
에 넣어야 합니다.
공식문서에 따른 method_exchangeImplementations
동작 방식은 다음과 같습니다.
IMP imp1 = method_getImplementation(m1);
IMP imp2 = method_getImplementation(m2);
method_setImplementation(m1, imp2);
method_setImplementation(m2, imp1);
다시 메소드를 호출해보면 두 메소드의 기능이 바뀐 것을 확인할 수 있습니다.