Swift 方法交换

代码:


import UIKit

protocol SwizzlingProtocol: class {
    static func awake()
    static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector)
}

extension SwizzlingProtocol {
    
    static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
        let originalMethod = class_getInstanceMethod(forClass, originalSelector)
        let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
        guard (originalMethod != nil && swizzledMethod != nil) else {
            return
        }
        if class_addMethod(forClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!)) {
            class_replaceMethod(forClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
        } else {
            method_exchangeImplementations(originalMethod!, swizzledMethod!)
        }
    }
}

class SwizzlingTool {
    static func searchAndExecuteAwake() {
        let typeCount = Int(objc_getClassList(nil, 0))
        let types = UnsafeMutablePointer.allocate(capacity: typeCount)
        let autoreleasingTypes = AutoreleasingUnsafeMutablePointer(types)
        objc_getClassList(autoreleasingTypes, Int32(typeCount))
        for index in 0 ..< typeCount {
            (types[index] as? SwizzlingProtocol.Type)?.awake()
        }
        types.deallocate()
    }
}

extension UIApplication {
    private static let runOnce: Void = {
        SwizzlingTool.searchAndExecuteAwake()
    }()
    
    override open var next: UIResponder? {
        UIApplication.runOnce
        return super.next
    }
}

正确的使用方式

class ViewController: UIViewController, SwizzlingProtocol{
    static func awake() {
        swizzleMethod
    }
    private static let swizzleMethod: Void = {
        let originalSelector = #selector(new_viewWillAppear(_:))
        let swizzledSelector = #selector(swizzled_new_viewWillAppear(_:))
        
        swizzlingForClass(ViewController.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
    }()
    
    @objc dynamic func swizzled_new_viewWillAppear(_ animated: Bool) {
        swizzled_new_viewWillAppear(animated)
        print("swizzled_viewWillAppear")
    }
    
    
    @objc dynamic func new_viewWillAppear(_ animated: Bool) {

        print("new_viewWillAppear")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.new_viewWillAppear(true)
    }
}

错误一、
去除 swizzled_new_viewWillAppear 前的dynamic 标记
引发的问题:循环调用直到奔溃

错误二,
去除 new_viewWillAppear 前的dynamic 标记
引发的问题:方法交换无效

问题原因

详细见stackoverflow:
https://stackoverflow.com/questions/33096873/method-swizzling-does-not-work

总结:
在swift中实现方法交换必须满足以下条件:
1,类class必须继承于NSObject
2,被交换的两个方法前必须用dynamic标记

你可能感兴趣的:(Swift 方法交换)