当前位置: 首页 > news >正文

SwizzleMethod 黑魔法

首先,请加入runtime头文件 #import <objc/runtime.h>

    void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
    {
        // the method might not exist in the class, but in its superclass
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        // class_addMethod will fail if original method already exists
        BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        
        // the method doesn’t exist and we just added one
        if (didAddMethod) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }
        else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }

上面这个C风格函数,就是SwizzleMethod的核心方法,用来交换Runtime中类和对象的方法接口指针。但是这有什么用呢?

你知道有名的第三方库IQKeyboard么?

这个吊库,不需要引入头文件,不需要调用任何方法就能使用。怎么做到的呢?
答案是NSObject的 + (void)load方法。

这个类方法,在软件运行时一定会调用一次,并且不需要调用super方法,因为父类的load方法也一定会调用。

IQKeyboard就是在load方法中初始化的。

SwizzleMethod应用实例 —— 无痛手术

这个比喻并不准确,准确说应该是无痕手术 —— 对方法的无痕手术
首先给AppDelegate添加Category,可以放在新文件中哦,比如AppDelegate+Extension.h & m。

+ (void)load
{
    swizzleMethod([AppDelegate class], @selector(application:didFinishLaunchingWithOptions:), @selector(swizzle_application:didFinishLaunchingWithOptions:));
}

这里,我们把AppDelegate的启动方法更换成了我们自己的swizzle_application:didFinishLaunchingWithOptions方法。两个方法指针互换,然后我们在我们的方法中加入我们需要的代码。

- (BOOL)swizzle_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //我们需要添加的代码
    //
    return [self swizzle_application:application didFinishLaunchingWithOptions:launchOptions];
}

注意到了么,结尾我们自己调用swizzle_application:application方法,因为这个这个方法指针实际已经指向AppDelegateapplication:didFinishLaunchingWithOptions方法。其他地方掉用AppDelegateapplication:didFinishLaunchingWithOptions方法则会指向我们的swizzle_application:application方法,这样我们就在人不知不觉中,向AppDelegate插入了一段代码,这一切不需要AppDelegate引入任何头文件,是不是很Cool?

这样一来就可以把需要放在这里面的各种监测代码初始化,都放到我们的swizzle_application:application方法中,可以给这个方法新建一个类,每次新建工程直接拖进来一起编译,分分钟植入,帅爆一切,点个赞吧。

相关文章:

  • bootstrap-wysiwyg整合ajaxFileUpload实现图片实时上传刷新
  • 别成为网络安全垃圾数据收藏家
  • msyql 笔记
  • python连接sql server数据库
  • Mysql详解my-innodb-heavy-4G.cnf 配置
  • 为什么说Ubuntu的运行级别为2
  • python网络编程1
  • Exchange 跨林迁移 Part7 配置密钥服务器
  • SQLserver行转列与列转行
  • d3js shape深入理解
  • 解决WordPress安装主题/插件提示输入FTP帐号的问题
  • jdk 7下载地址
  • leetcode Longest Common Prefix
  • Javascript之sort深入探究
  • Java中继承的规则
  • Asm.js的简单介绍
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • CODING 缺陷管理功能正式开始公测
  • CSS 专业技巧
  • leetcode98. Validate Binary Search Tree
  • mysql常用命令汇总
  • nodejs实现webservice问题总结
  • Python3爬取英雄联盟英雄皮肤大图
  • react 代码优化(一) ——事件处理
  • Redis学习笔记 - pipline(流水线、管道)
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • windows-nginx-https-本地配置
  • 初识 webpack
  • 动态魔术使用DBMS_SQL
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 理清楚Vue的结构
  • 如何实现 font-size 的响应式
  • 什么是Javascript函数节流?
  • 项目实战-Api的解决方案
  • 用Python写一份独特的元宵节祝福
  • 正则表达式
  • 从如何停掉 Promise 链说起
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 我们雇佣了一只大猴子...
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • # Maven错误Error executing Maven
  • #define与typedef区别
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (windows2012共享文件夹和防火墙设置
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (二)linux使用docker容器运行mysql
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • ***检测工具之RKHunter AIDE
  • .dwp和.webpart的区别
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .NET 反射的使用
  • .netcore 获取appsettings