UIView 方法 swizzling swift 3

Posted

技术标签:

【中文标题】UIView 方法 swizzling swift 3【英文标题】:UIView method swizzling swift 3 【发布时间】:2017-02-19 08:21:03 【问题描述】:

我正在尝试根据答案 How to implement method swizzling swift 3.0? 在 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]: 无法识别的选择器发送到实例 0x7fc7c8820400'

我不明白为什么 swizzled_localization_awakeFromNib 调用 UINavigationController。我在 obj-c 项目中使用它,这可能是原因吗?它在 swift 2 throught dispatch_once 中运行良好。

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

【问题讨论】:

【参考方案1】:

问题是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)
    

【讨论】:

是的,已经知道了。在发布我自己的答案后找到你的答案:)

以上是关于UIView 方法 swizzling swift 3的主要内容,如果未能解决你的问题,请参考以下文章

swift class type isa-swizzling

XCode UI 测试 swizzle API 类方法

UIView 子类的 Swift 通用方法

swift UIView 扩展

什么是method swizzling

Firebase 消息传递方法 swizzling 不起作用