As I know, method swizzling with method_exchangeImplementations(A, B) function exchanges A method and B method in runtime.
If I get method with:
let A = class_getInstanceMethod(UIViewController.self, #selector(UIViewController.viewDidAppear))
it looks like Swift runtime replaces viewDidAppear method of UIViewController class -- superclass of SomeViewController inherits from.
But as I know, inheritance works on compile time, not in a runtime. In this case, how do they know, on runtime, that which superclass method (swizzled method or original method) should be called?
Here is simple example
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let originalMethod = class_getInstanceMethod(UIViewController.self, #selector(UIViewController.viewDidAppear))
let swizzledMethod = class_getInstanceMethod(UIViewController.self, #selector(UIViewController.s_viewDidAppear))
if let originalMethod, let swizzledMethod {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
return true
}
UIViewController+S.swift
extension UIViewController {
func s_viewDidAppear(_ animated: Bool) {
print("s_viewDidAppear")
}
}
SViewController.swift
class SViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("SViewController.viewDidAppear")
}
}
and this prints
s_viewDidAppear
SViewController.viewDidAppear
I expected only SViewController.viewDidAppear prints since inheritance works on compile time, and viewDidAppear method is swapped. And now I think runtime only swaps viewDidAppear of UIViewController because s_viewDidAppear is being printed. And this became conflict to me.
It's Objective-c's runtime, despite that it's implemented in Swift. Better to implement it with Objective-C to avoid confusions.
It's sending messages, instead of calling functions. In compile time is determined, that super class is
UIViewController, and you will sending message with selector@selector(viewDidAppear). Then when application executing, runtime will just receive message: call implementation of[UIViewController class]withviewDidAppearselectior.You have exchanged implementations at app start, so new one will be called instead. Btw you should have such implementation to call original code:
Missing super's
viewDidAppearcan break something.