Reputation: 716
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.
Upvotes: 0
Views: 115
Reputation: 4615
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]
with viewDidAppear
selectior.
You have exchanged implementations at app start, so new one will be called instead. Btw you should have such implementation to call original code:
extension UIViewController {
func s_viewDidAppear(_ animated: Bool) {
s_viewDidAppear(animated)
print("s_viewDidAppear")
}
}
Missing super's viewDidAppear
can break something.
Upvotes: 1