代码:
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<AnyClass>.allocate(capacity: typeCount)
let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(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
标记