关于Method Swizzling 原理什么的有不少帖子讲述的已经很清楚这里再也不赘述,swift
这里仅仅处理Method Swizzling 在swift4.0中的使用方法api
由于Swift自己对Runtime的支持并非很到位,尤为是Method-Swizzling在OC中很是经常使用,可是到Swift后发现
load
方法不见了进而须要用initialize
代替,甚至到了Swift4中直接取消了initialize
方法。所以须要本身初始化app解决方案须要在appdelegate 添加这一行代码
UIViewController.initializeMethod()async
/** 须要在appdelegate 添加这一行代码 UIViewController.initializeMethod() */
private let onceToken = "Method Swizzling" extension UIViewController { public class func initializeMethod() { // Make sure This isn't a subclass of UIViewController, So that It applies to all UIViewController childs if self != UIViewController.self { return } //DispatchQueue函数保证代码只被执行一次,防止又被交换回去致使得不到想要的效果 DispatchQueue.once(token: onceToken) { let originalSelector = #selector(UIViewController.viewWillAppear(_:)) let swizzledSelector = #selector(UIViewController.swizzled_viewWillAppear(animated:)) let originalMethod = class_getInstanceMethod(self, originalSelector) let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) //在进行 Swizzling 的时候,须要用 class_addMethod 先进行判断一下原有类中是否有要替换方法的实现 let didAddMethod: Bool = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!)) //若是 class_addMethod 返回 yes,说明当前类中没有要替换方法的实现,因此须要在父类中查找,这时候就用到 method_getImplemetation 去获取 class_getInstanceMethod 里面的方法实现,而后再进行 class_replaceMethod 来实现 Swizzing if didAddMethod { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!)) } else { method_exchangeImplementations(originalMethod!, swizzledMethod!) } let originalSelector1 = #selector(UIViewController.viewWillDisappear(_:)) let swizzledSelector1 = #selector(UIViewController.swizzled_viewWillDisappear(animated:)) let originalMethod1 = class_getInstanceMethod(self, originalSelector1) let swizzledMethod1 = class_getInstanceMethod(self, swizzledSelector1) //在进行 Swizzling 的时候,须要用 class_addMethod 先进行判断一下原有类中是否有要替换方法的实现 let didAddMethod1: Bool = class_addMethod(self, originalSelector1, method_getImplementation(swizzledMethod1!), method_getTypeEncoding(swizzledMethod1!)) if didAddMethod1 { class_replaceMethod(self, swizzledSelector1, method_getImplementation(originalMethod1!), method_getTypeEncoding(originalMethod1!)) } else { method_exchangeImplementations(originalMethod1!, swizzledMethod1!) } } } @objc func swizzled_viewWillAppear(animated: Bool) { //须要注入的代码写在此处 self.swizzled_viewWillAppear(animated: animated) DDLOG(message: "\(NSStringFromClass(classForCoder))--Appear") } @objc func swizzled_viewWillDisappear(animated: Bool) { //须要注入的代码写在此处 self.swizzled_viewWillDisappear(animated: animated) DDLOG(message: "\(NSStringFromClass(classForCoder))--Disappear") } }
因为swift 没有DispatchQueue.once 方法 因此手动扩展了一个 方便使用函数
extension DispatchQueue { private static var _onceTracker = [String]() public class func once(token: String, block: () -> ()) { objc_sync_enter(self) defer { objc_sync_exit(self) } if _onceTracker.contains(token) { return } _onceTracker.append(token) block() } func async(block: @escaping ()->()) { self.async(execute: block) } func after(time: DispatchTime, block: @escaping ()->()) { self.asyncAfter(deadline: time, execute: block) } }