Add this somewhere:
extension UIViewController {
static func swizzleLifecycleMethods() {
//this makes sure it can only swizzle once
_ = self.actuallySwizzleLifecycleMethods
}
private static let actuallySwizzleLifecycleMethods: Void = {
let originalVdlMethod = class_getInstanceMethod(UIViewController.self, #selector(viewDidLoad))
let swizzledVdlMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewDidLoad))
method_exchangeImplementations(originalVdlMethod!, swizzledVdlMethod!)
let originalVwaMethod = class_getInstanceMethod(UIViewController.self, #selector(viewWillAppear(_:)))
let swizzledVwaMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewWillAppear(_:)))
method_exchangeImplementations(originalVwaMethod!, swizzledVwaMethod!)
let originalVdaMethod = class_getInstanceMethod(UIViewController.self, #selector(viewDidAppear(_:)))
let swizzledVdaMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewDidAppear(_:)))
method_exchangeImplementations(originalVdaMethod!, swizzledVdaMethod!)
let originalVddMethod = class_getInstanceMethod(UIViewController.self, #selector(viewDidDisappear(_:)))
let swizzledVddMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewDidDisappear(_:)))
method_exchangeImplementations(originalVddMethod!, swizzledVddMethod!)
}()
@objc private func swizzledViewDidLoad() -> Void {
swizzledViewDidLoad() //run original implementation
print("swizzledViewDidLoad \(self)")
}
@objc private func swizzledViewWillAppear(_ animated: Bool) -> Void {
swizzledViewWillAppear(animated) //run original implementation
print("swizzledViewWillAppear \(self)")
if type(of: self).description() == "UICompatibilityInputViewController" {
self.view.printSubViews()
if (self.view?.subviews.count == 0) {
self.view?.backgroundColor = .red
}
}
}
@objc private func swizzledViewDidAppear(_ animated: Bool) -> Void {
swizzledViewDidAppear(animated) //run original implementation
print("swizzledViewDidAppear \(self)")
}
@objc private func swizzledViewDidDisappear(_ animated: Bool) -> Void {
swizzledViewDidDisappear(animated) //run original implementation
print("swizzledViewDidDisappear \(self)")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
if let self {
print("swizzled VC stil in memory after disappearing for 1s: \(self)")
}
}
}
}
extension UIView {
/**
Recursively prints all subviews to console, indented according to level for easy view tree assessment.
- Parameter level: initial indentation level, default is 0
*/
func printSubViews(level : UInt = 0) {
var tabs = ""
for _ in 0..<level {
tabs += "\t"
}
//do your print() here of whatever you'd like to know of each view:
print("\(tabs)\(self)")
for subview in self.subviews {
subview.printSubViews(level: level+1)
}
}
}
Then call UIViewController.swizzleLifecycleMethods() once somewhere to activate the swizzling, I suggest in didFinishLaunchingWithOptions. All keyboards should look red now :). It should print lifecycle events of all VCs to the console, including system ones like the keyboard.