Method Dispatch 시리즈 대망의 3탄 method swizzling
이건 또 무엇인고.. 하면서 찾아보니 의미는 한줄로 간단하게 적혀있었다.
런타임 시점에 기존 메서드를 다른 메서드로 바꾸어 실행하는 것.
사실 이 의미를 보고 들었던 궁금증이 몇가지 있었는데 대충 이랬다.
1. 굳이 런타임 시점에 다른 메서드로 바꿔줘야할 필요나 이유가 있는지?
2. 시스템 상으로 구현되어 있는 메서드에 swizzling을 적용시킬 수 있다는데, 그렇게 했다가 에러나면 어떡함? 안 쓰는 게 좋은 거 아님?
활용 방법도 알아보고 궁금증도 해결해보는 걸로~
Method Swizzling 구현하기
Q: Method Swizzling 어떻게 구현하나요?
A: method_exchangeImplementations() 메서드를 사용합니다.
extension UIViewController {
class func swizzleMethod() {
let originalSelector = #selector(UIViewController.viewDidAppear(_:))
let swizzledSelector = #selector(UIViewController.swizzledViewWillAppear(animated:))
guard let originalMethod = class_getInstanceMethod(UIViewController.self, originalSelector),
let swizzledMethod = class_getInstanceMethod(UIViewController.self, swizzledSelector) else { return }
method_exchangeImplementations(originalMethod, swizzledMethod) // 이 부분에서 method swizzling이 발생함!
}
@objc public func swizzledViewWillAppear(animated: Bool) {
print("swizzled view will appear")
}
}
UIViewController의 extension으로 메서드를 선언해주고,
앱 시작 시점에 이 메서드를 실행시켜주어야 한다.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIViewController.swizzleMethod()
return true
}
이렇게 하면 바뀐 메서드가 실행되는 것을 확인할 수 있음.
뒤늦게 해결해보는 궁금증
Q. 굳이 런타임 시점에 다른 메서드로 바꿔줘야할 필요나 이유가 있는지?
A. 위처럼 viewWillAppear를 실행할 때마다 실행시켜줘야할 로직이 있다거나 한다면 swizzling이 편할 수 있음. 기존의 방식대로 커스텀 뷰 컨트롤러의 viewWillAppear를 오버라이딩해서 구현하면 모든 화면에다가 구현해줘야해서 중복되는 코드가 늘어나니까!
Q. 시스템 상으로 구현되어 있는 메서드에 swizzling을 적용시킬 수 있다는데, 그렇게 했다가 에러나면 어떡함? 안 쓰는 게 좋은 거 아님?
A. 그래서 남용하는 게 좋지는 않다고 함(?). 상황에 따라 적절하게 쓰는 게 좋다!
Q. 왜 런타임에서 메서드를 바꿔줘야만 하는가?
A. 이건 나름대로의 생각인데 클래스의 메서드를 동적 디스패치를 통해 런타임에 어떤 메서드를 실행하는 지 결정하는 것처럼 컴파일러가 어떤 메서드를 실행할지 결정할 수 없으므로 런타임에서 실행을 결정하도록 하는 것이 아닐까 싶음.. 어떻게 보면 당연한 거 같은데 장황하게 정리해보았다..
'Swift' 카테고리의 다른 글
[Swift] sync, async, serial, concurrent (0) | 2023.01.17 |
---|---|
[Swift] Safe Index (0) | 2023.01.07 |
[Swift] dynamic var, @objc, @NSManaged (0) | 2023.01.07 |
[Swift] final (feat. Method Dispatch) (0) | 2023.01.05 |
#0. 목적 (0) | 2020.04.14 |