UIView method swizzling swift 3

僤鯓⒐⒋嵵緔 提交于 2019-12-11 02:21:55

问题


I'm trying to implement method swizzling in swift 3 basing on answer How to implement method swizzling swift 3.0?

Here's my code:

// MARK: - Swizzling

private let swizzling: (UIView.Type) -> () = { view in
    let originalSelector = #selector(view.awakeFromNib)
    let swizzledSelector = #selector(view.swizzled_localization_awakeFromNib)

    let originalMethod = class_getInstanceMethod(view, originalSelector)
    let swizzledMethod = class_getInstanceMethod(view, swizzledSelector)

    method_exchangeImplementations(originalMethod, swizzledMethod)
}

extension UIView {

    open override class func initialize() {
        guard self === UIView.self else {
            return
        }

        swizzling(self)
    }

    func swizzled_localization_awakeFromNib() {
        swizzled_localization_awakeFromNib()

        if let localizableView = self as? Localizable {
            localizableView.localize()
        }
    }

}

But on app launch it crashes with reason:

'-[UINavigationController swizzled_localization_awakeFromNib]: unrecognized selector sent to instance 0x7fc7c8820400'

I can't figure out why swizzled_localization_awakeFromNib called on UINavigationController. I am using this in obj-c project, can it be the reason? It worked fine in swift 2 throught dispatch_once.

I tried place breakpoint before swizzling(self), and it called once on UIView, as expected.


回答1:


The problem is that awakeFromNib is a method of NSObject and not of UIView. Your code swizzles the NSObject method with a method of UIView, and calling the original method crashes when the swizzled method is called on UINavigationController (or any other subclass of NSObject which is not a subclass of UIView).

The solution is to try to add the swizzled method with the original name first (as described in http://nshipster.com/method-swizzling/):

private let swizzling: (UIView.Type) -> () = { view in
    let originalSelector = #selector(view.awakeFromNib)
    let swizzledSelector = #selector(view.swizzled_localization_awakeFromNib)

    let originalMethod = class_getInstanceMethod(view, originalSelector)
    let swizzledMethod = class_getInstanceMethod(view, swizzledSelector)

    let didAddMethod = class_addMethod(view, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
    if didAddMethod {
        class_replaceMethod(view, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}


来源:https://stackoverflow.com/questions/42325078/uiview-method-swizzling-swift-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!