I want to log some statements in deinit in each subclass of UIViewController in my project. I don't want to copy/paste the same lines in each view controller subclass.
There is a way to achieve this.
You can't swizzle deinit
, but you can swizzle another method like viewDidLoad
to poison the class with associatedObject
. When viewController deallocates, the associatedObject gets deallocated as well.
final class Deallocator {
var closure: () -> Void
init(_ closure: @escaping () -> Void) {
self.closure = closure
}
deinit {
closure()
}
}
private var associatedObjectAddr = ""
extension UIViewController {
@objc fileprivate func swizzled_viewDidLoad() {
let deallocator = Deallocator { print("Deallocated") }
objc_setAssociatedObject(self, &associatedObjectAddr, deallocator, .OBJC_ASSOCIATION_RETAIN)
swizzled_viewDidLoad()
}
static let classInit: Void = {
let originalSelector = #selector(viewDidLoad)
let swizzledSelector = #selector(swizzled_viewDidLoad)
let forClass: AnyClass = UIViewController.self
let originalMethod = class_getInstanceMethod(forClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}()
}
Caveat
The closure will not get called exactly when viewController is deallocated, since the Deallocator
is deallocated after viewController is completely deallocated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With