Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to swizzle deinit using swift. if yes then how to achieve this

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.

like image 810
ZaEeM ZaFaR Avatar asked Sep 03 '25 15:09

ZaEeM ZaFaR


1 Answers

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.

like image 131
farzadshbfn Avatar answered Sep 05 '25 05:09

farzadshbfn



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!