UIView 方法调配 swift 3

UIView method swizzling swift 3

我正在尝试根据答案

在 swift 3 中实现方法混合

这是我的代码:

// 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()
        }
    }

}

但是在应用程序启动时它崩溃了,原因是:

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

我不明白为什么 swizzled_localization_awakeFromNib 调用了 UINavigationController。我在obj-c项目中使用这个,会不会是这个原因?它在 swift 2 到 dispatch_once.

期间运行良好

我尝试在 swizzling(self) 之前放置断点,它按预期在 UIView 上调用了一次。

问题是 awakeFromNibNSObject 的一个方法并且 不属于 UIView。您的代码将 NSObject 方法与 UIView 的方法,调用原方法崩溃 当在 UINavigationController 上调用 swizzled 方法时 (或 NSObject 的任何其他子类,但不是 UIView 的子类)。

解决方法是尝试添加 swizzled 方法 原名在前(如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)
    }
}