swizzling, 말 그대로 '휘젓기' 라는 의미를 가지고 있다.
직역하자면, 함수 휘젓기 인데 의미는 다음과 같다.
런타임 시점에 기존 메서드의 구현을 다른 메서드로 교체하여 동작을 변경하는 기법입니다.
하는 일은 간단하다.
바꿔치기로 함수가 실행 될 때마다 작성한 함수가 대신 동작하게 한다.
import UIKit
import ObjectiveC.runtime
extension UIViewController {
// Swizzling을 수행하는 메서드
static func swizzleViewWillAppear() {
guard
let originalMethod = class_getInstanceMethod(self, #selector(viewWillAppear(_:))),
let swizzledMethod = class_getInstanceMethod(self, #selector(swizzled_viewWillAppear(_:)))
else { return }
method_exchangeImplementations(originalMethod, swizzledMethod)
}
// Swizzled 메서드
@objc func swizzled_viewWillAppear(_ animated: Bool) {
// 공통 로직 추가
print("ViewWillAppear: \(self)")
// 원래의 viewWillAppear 호출
swizzled_viewWillAppear(animated)
}
}
우선적으로 method swizzling 기능은 Objective-C 런타임 기능이기 때문에 Swift 메서드를 Objective-C와 호환되게 만들어줘야 한다.
class_getInstanceMethod 메서드를 통해 호출한 타겟 클래스에서 #selector로 넣어준 메서드를 해당 클래스에서 찾아준다.
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIViewController.swizzleViewWillAppear()
return true
}
Appdelegate 단에서 해당 클래스의 메서드를 swizzling 하는 메서드를 호출하여 바꿔친다.
Objective-C는 동적인 언어이므로, 어떤 코드가 실행 될 지가 런타임 시점에 결정된다.
반대로 swift는 기본적으로 정적인 언어이므로 dynamic 키워드를 통해 Objective-C 런타임에 디스패치 됨을 명시하여야 Method swizzling 기능을 사용할 수 있다.
그렇다는 건 swizzling 할 대상이 되는 method는 런타임에 동작이 결정되어야 함을 의미한다.
그리고 기본적으로 iOS에서 기본 구현된 메서드를 건드는 거라 추후 구현이 변경될 경우, 번거로워 질 수 있다.

예시로 든 viewWillAppear 또한 dynamic 키워드를 적용되어 있다.
간단한 예를 들자면 위에서 쓰인 예시로, viewWillAppear를 swizzling하여 화면 노출 수를 로그로 확인한다든지와 같은 공통 로직을 적용하고 싶을 때 사용될 수 있다.
@objc func swizzled_viewWillAppear(_ animated: Bool) {
print("ViewWillAppear: \(self)")
// 원래의 viewWillAppear를 호출하고 싶을 때는?
// 실제로는 swizzle된 원래 메서드가 이 이름을 가지고 있음!
swizzled_viewWillAppear(animated)
}
얼핏 보면 무한 재귀에 빠질 것 같지만...
해당 함수는 런타임 시점에 실행되고 swizzling 된다.
그렇다는 건 viewWillApeear가 동작해야 하는 시점에 위의 예시 메서드가 실행되는 동시에 swizzling 되어 swizzled_viewWillAppear 메서드는 기존 ViewWillApeear가 되어 버린다.