文档章节

关于Swift4.0 Method Swizzling(iOS的hook机制)使用

冰泪_
 冰泪_
发布于 2018/09/26 14:13
字数 612
阅读 567
收藏 0

关于Method Swizzling 原理什么的有很多帖子讲述的已经很清楚这里不再赘述,

这里仅仅处理Method Swizzling 在swift4.0中的使用方法

因为Swift本身对Runtime的支持并不是很到位,尤其是Method-Swizzling在OC中非常常用,但是到Swift后发现load方法不见了进而需要用initialize代替,甚至到了Swift4中直接取消了initialize方法。因此需要自己初始化

解决方案需要在appdelegate 添加这一行代码
 UIViewController.initializeMethod()

/**
 需要在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)
    }
}

 

© 著作权归作者所有

冰泪_
粉丝 16
博文 90
码字总数 64127
作品 0
青浦
程序员
私信 提问
如何实现一个IOS网络监控组件

此文由作者朱志强授权网易云社区发布。 Mobile Application Monitor IOS组件设计技术分享 背景 应用程序性能管理Application Performance Management(APM)是近年来比较火的互联网产业, Mo...

网易云
2018/12/11
0
0
运行时Hook所有Block方法调用的技术实现

本技术实现在YSBlockHook中。 1.方法调用的几种Hook机制 iOS系统中一共有:C函数、Block、OC类方法三种形式的方法调用。Hook一个方法调用的目的一般是为了监控拦截或者统计一些系统的行为。H...

欧阳大哥2013
03/31
0
0
面向切面编程:Aspects源码解析

面向切面编程 所谓的面向切面编程(AOP),原理就是在不更改正常业务的流程的前提下,通过一个动态代理类,实现对目标对象嵌入的附加的操作。 简单说,就是在不影响我们现在正常业务的情况下...

Sunxb
05/23
0
0
one-stop-shop for all your method swizzling needs

JRSwizzle Description JRSwizzle is source code package that offers a single, easy, correct+consistent interface for exchanging Objective-C method implementations ("method swizzl......

mingxun
2014/04/27
58
0
iOS逆向之旅(进阶篇) — HOOK(Method Swizzling)

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:656315826,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习...

_小迷糊
2018/10/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

ES6

ES6:不改变原理的基础上,让API变得更简单 一、let:代替var用于声明变量 1、var的缺点: (1)声明提前 (2)没有块级作用域 2、let的优点: (1)组织了申明提前 (2)让let所在的块({}),...

wytao1995
今天
3
0
kubernetes 环境搭建 —— minikube

创建集群 minikube start 搭建好 k8s 集群后,可以查看集群的状态以及部署应用。主要用到的是 k8s 的 api,这通常需借助于 kutectl 命令行工具 基本操作 kubectl versionkubectl cluster-i...

lemos
今天
9
0
关于js混淆与反混淆还原操作

使用js的混淆加密,其目的是为了保护我们的前端代码逻辑,对应一些搞技术吃饭的公司来说,为了防止被竞争对手抓取或使用自己的代码,就会考虑如何加密,或者混淆js来达到代码保护。 1、为什么...

开源oschina
今天
11
0
用盛金公式解三次方程(ansi c版)

/* cc cubic.c -lm gcc cubic.c -lm Shengjin's Formulas Univariate cubic equation aX ^ 3 + bX ^ 2 + cX + d = 0, (a, b, c, d < R, and a!= 0). Multiple root disc......

wangxuwei
今天
9
0
JBolt开发平台入门(16)- 弹出Dialog显示指定区域的html内容

在JBolt里,有个主从表Demo。 子表中除了普通的table显示,还有其它从表显示形式 比如下方案例:是针对一个升级管理子表中存放版本的changelog富文本信息。 需求是点击左上角的弹出查看按钮,...

山东-小木
今天
46
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部