Method Swizzle黑魔法,修改 ios 系统类库方法(转载)

一般来说,系统提供的方法已经足够开发了,但是有的时候有些需求用普通方法不好做。

如:在所有的viewcontroll 的viewwillappear:方法之前打个log

你可能会这么做:

1. 建一个uiviewcontroll 父类,重写viewwillappear方法,调用super viewwillappear 方法之前加上log

2. 所有新建的uiviewcontroller 继承第一步生成的

确实你是完成这样的功能,可是你做了那么多的修改,基本每个uiviewcontroller都去修改了父类,这种方法太过于笨重了

 

本文提供了简单地方法即可实现

我的理解中,object-c 的类调用方法是根据三个元素来定义的。 

1. 方法,代表类定义中一个方法类型(typedef struct objc_method *Method)

2. SEL 选择器(typedef struct objc_selector *SEL),一个方法在运行时的名字,常见的有 [self performSelector:@selector(somemethod:) withObject:nil afterDelay:0.5]; @selector(somemethod:)作为方法的入口

3. 方法的实现入口(typedef id (*IMP)(id, SEL, …))

这三个元素确定了具体调用哪一个函数

 

直接看代码

 

[objc] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #import "UIViewController+Tracking.h"  
  2. #import <objc/runtime.h>  
  3.   
  4. @implementation UIViewController (Tracking)  
  5.   
  6. + (void)load {  
  7.     NSString *className = NSStringFromClass(self.class);  
  8.     NSLog(@"classname %@", className);  
  9.     static dispatch_once_t onceToken;  
  10.     dispatch_once(&onceToken, ^{  
  11.         Class class = [self class];  
  12.           
  13.         // When swizzling a class method, use the following:  
  14.         // Class class = object_getClass((id)self);  
  15.           
  16.         SEL originalSelector = @selector(viewWillAppear:);  
  17.         SEL swizzledSelector = @selector(xxx_viewWillAppear:);  
  18.           
  19.         Method originalMethod = class_getInstanceMethod(class, originalSelector);  
  20.         Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);  
  21.           
  22.         BOOL didAddMethod =  
  23.         class_addMethod(class,  
  24.                         originalSelector,  
  25.                         method_getImplementation(swizzledMethod),  
  26.                         method_getTypeEncoding(swizzledMethod));  
  27.           
  28.         if (didAddMethod) {  
  29.             class_replaceMethod(class,  
  30.                                 swizzledSelector,  
  31.                                 method_getImplementation(originalMethod),  
  32.                                 method_getTypeEncoding(originalMethod));  
  33.         } else {  
  34.             method_exchangeImplementations(originalMethod, swizzledMethod);  
  35.         }  
  36.     });  
  37. }  

 

我们category重写了NSObject的 load 方法oc提供了objc/runtime.h类让我们获取这些东西,同时还提供了对类方法操作的函数

我们想的是,直接用一个方法替换掉系统的方法,然后把一些自定义的动作加到方法中

我们只想运行一次就够了,所以使用了 dispatch_once(&onceToken, ^{ …… }
接下来给类添加了新方法

把新方法和系统方法替换

 

 

[objc] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #pragma mark - Method Swizzling  
  2.   
  3. - (void)xxx_viewWillAppear:(BOOL)animated {  
  4.     NSLog(@"viewWillAppear: %@", self);  
  5.     [self xxx_viewWillAppear:animated];  
  6. }  

但是新方法实现的时候,调用的是 [self xxx_viewwillAppear:animated]; 可能你会疑惑

 

这是因为我们在上面已经用xxx_viewwillAppear 和 viewwillAppear 互换了。所以实际上执行的是系统的viewwillAppear

这个时候可能你又有疑问了,为什么实现是- (void)xxx_viewWillAppear:(BOOL)animated{} 这样的

这是因为 SEL swizzledSelector = @selector(xxx_viewWillAppear:); 拿的就是我们新写的方法。

可以结合这篇博客看,配图很容易懂

http://blog.csdn.net/yiyaaixuexi/article/details/9374411

 

以及这篇对SEL讲的比较清楚

http://blog.csdn.net/fengsh998/article/details/8612969

代码下载地址

https://github.com/holysin/Method_swizzle

1  Method nameMethod = class_getInstanceMethod(Class class,SEL name);//得到实例方法

参数:class类名  name 方法名

理解:通过类名和方法名来得到方法(c函数)

 

2 method_getImplementation(Method method)

参数:method 方法

理解:通过方法来得到它的实现

 

 

3 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

理解:将所给的name(方法名)的方法实现,被imp(方法的实现)代替

cls:被添加方法的类

name:可以理解为方法名,这个貌似随便起名,

imp:实现这个方法的函数 

types:一个定义该函数返回值类型和参数类型的字符串,这个具体会在后面讲

 

4 class_replaceMethod(Class class,SEL  B, method_getImplementation(Method AMethod), method_getTypeEncoding(Method AMethod));

参数:class :方法所属的类 B:将被替换其实现的方法名    AMethod:由A生成的方法(c函数)

理解:用A的方法实现来代替B的方法实现

5 method_exchangeImplementations(SEL A, SEL B);

理解:交换两个方法的实现

void swizzle_method(Class class,SEL originalSelector,SEL swizzledSelector) {

    Method originalMethod = class_getInstanceMethod(class, originalSelector);//得到实例方法

    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didSwizzleMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));

    if (didSwizzleMethod) {

        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));

    } else {

        method_exchangeImplementations(originalMethod, swizzledMethod);

    }

}

 

 

转载于:https://www.cnblogs.com/HughLiu/p/4648105.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/375731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win10无法开启夜间模式

在学校的时候没感觉&#xff0c;一进公司发现电脑还是需要设置一下护眼的&#xff0c;但是在设置的时候却遇到夜间模式无法开启的问题。 首先在左下角搜索设备管理器 找到显示适配器 查看显示器设备状态 如果设备图标上有黄三角感叹号则说明该设备驱动有问题&#xff0c;需要…

Linux LVM学习总结——扩展卷组VG

Linux服务器由于应用变更或需求的缘故&#xff0c;有可能出现分区空间不足的情况&#xff0c;此时往往需要进行扩容&#xff08;要增加分区的空间&#xff09;&#xff0c;而采用LVM的好处就是可以在不需停机的情况下可以方便地调整各个分区大小。如下所示&#xff0c;分区/u05…

【液晶模块系列基础视频】1.3.iM_TFT30模块简介

【液晶模块系列基础视频】1.3.iM_TFT30模块介绍 技术论坛&#xff1a;http://www.eeschool.org 博客地址&#xff1a;http://xiaomagee.cnblogs.com 官方网店&#xff1a;http://i-board.taobao.com 银杏科技 GINGKO TECH. 保留权利&#xff0c;转载请注明出处 本次教学视频介…

C++控制向文件中写入浮点数的格式

有时会遇到向文件中写入一定格式的浮点数&#xff0c;为了对齐美观&#xff0c;常常采用控制小数点后的位数并用0补齐缺少的位数的方法。 #include <iostream> #include <iomanip> #include <fstream> using namespace std;int main(){double pi3.14;ofstre…

项目管理工具到底应该为谁服务?

项目管理工具到底应该为谁服务&#xff1f;为管理者&#xff0c;还是为了团队&#xff1b;为了管理报表&#xff0c;还是为了协作需求&#xff0c;这些是在项目管理工具选择或开发时需要面对和思考的一个问题。 传统项目管理工具在团队内部臭名昭著 项目管理工具当初都是为了项…

二叉树的递归定义及存储

定义 最多有两棵子树的有序树&#xff0c;称为二叉树。二叉树是一种特殊的树。 递归定义&#xff1a;二叉树是n(n>0)个有限结点构成的集合。N0称为空二叉树&#xff1b;n>0的二叉树由一个根结点和两互不相交的&#xff0c;分别称为左子树和右子树的二叉树构成。 二叉树中…

C++统计微妙级时间消耗(chrono)

有时我们需要统计某段程序运行所消耗的时间&#xff0c;通过C的chrono库&#xff0c;我们可以轻松实现这一需求&#xff0c;例如&#xff0c;我们求斐波那契数列消耗的时间。 #include <iostream> #include <chrono> #include <iomanip> using namespace st…

content-length与Transfer-Encoding: chunked的问题释疑

content-length与Transfer-Encoding: chunked的问题释疑 http返回头中content-length与Transfer-Encoding: chunked的问题释疑 先说说问题出现的背景&#xff1a; 公司服务器与手机客户端交互&#xff0c;客户端请求一个动态生成的XML文件&#xff0c;在用firebug查看http响应头…

基于RSA的加密/解密示例C#代码

在C#程序中&#xff0c;大家可能比较熟悉的方式是md5加密解密方式&#xff0c;对RSA可能并不是很熟悉&#xff0c; 下面就说一下RSA加密和解密的算法&#xff1a;using System;using System.Security.Cryptography;using System.Text;class RSACSPSample{static void Main(){tr…

iOS GorupBy

转自&#xff1a; IOS 数组分组 Grouped NSArray 12345678NSMutableSet *set[NSMutableSet set];[_list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {[set addObject:obj["MeasureType"]];//利用set不重复的特性,得到有多少组,根据数组中的…

android通过adb shell播放音乐

am start -n com.android.music/com.android.music.MediaPlaybackActivity -d /sdcard/timian.mp3拓展阅读 input keyevent 24 #增加音量 input keyevent 25 #降低音量 input keyevent 85 #暂停/播放 input keyevent 126 #恢复播放 input keyevent 127 #停止播放关闭音乐播放器…

NetBpm 安装篇(1)

尊重别人劳动成果 转载注明出处&#xff1a;http://www.cnblogs.com/anbylau2130/p/3875718.html 官方主页 http://www.netbpm.org/docs/install.html 文件目录 Netbpm的两种服务器配置 1&#xff0c;CassiniWebServer CassiniWebServer.exe是轻量级的web服务器&#xff0c;相…

python将文本中的数据处理成图像(matplotlib)

使用Python的matplotlib模块可以很方便的将数据处理成图表&#xff0c;使数据更加形象、直观。 #!/usr/bin/env pythonimport matplotlib.pyplot as plt import numpy as np from mpl_toolkits.axes_grid.anchored_artists import AnchoredTexty1np.loadtxt(ReadDataCostTime.…

string 中的 length函数 和size函数 返回值问题

string 中的 length函数 和 size函数 的返回值 ( 还有 char [ ] 中 测量字符串的 strlen 函数 ) 应该是 unsigned int 类型的 不可以 和 -1 比较。 应尽量避免 unsigned int 类型 和 int类型 数据 的比较 。当unsigned int 类型 和 int类型 数据 比较 时 &#xff0c;会 把…

交叉编译android版htop

编这个东西贼烦人。 话不多说&#xff0c;直接上教程 源代码版本&#xff1a;htop-2.2.0、ncurses-6.1 编译之前要确认自己有ndk&#xff0c;从【官网】直接下载&#xff0c;下载下来解压一下就能用。 先编ncurses 编译过程 ./configure CCarm-linux-androideabi-gcc-4.9 \-…

今天的一点点收获

今天怎么说呢&#xff0c;还是有点收获的&#xff0c;上午写了一上午的前端&#xff0c;然后就是下午又是一下午的c#&#xff0c;好特么酸爽啊&#xff0c;但是有一件特别蛋疼的事情发生了&#xff0c;我 天天叫的学长竟然不是学长而是学校的而老师&#xff0c;但是他们都不叫他…

jquery动态添加删除div--事件绑定,对象克隆

我想做一个可以动态添加删除div的功能。中间遇到一个问题&#xff0c;最后在manong123.com开发文摘 版主的热心帮助下解答了(答案在最后) 使用到的jquery方法和思想就是&#xff1a;事件的绑定和销毁(unbind)&#xff0c;另外还可以使用clone,通过克隆可以很好的解决这个问…

编程知识大杂烩

以下资料完全是随手记录&#xff0c;没有任何顺序或关联&#xff0c;需要用直接^F找就行了。 1. ps aux指令详解 http://blog.csdn.net/hanner_cheung/article/details/6081440 2. Linux下配置Apache php http://lelong.iteye.com/blog/904125 3. shell定义变量 http://see.xid…

最长公共前缀

2、最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 示例1 输入: ["flower","flow","flight"] 输出: "fl"示例2 输入: ["dog","racecar",…