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, …))
这三个元素确定了具体调用哪一个函数
直接看代码
- #import "UIViewController+Tracking.h"
- #import <objc/runtime.h>
- @implementation UIViewController (Tracking)
- + (void)load {
- NSString *className = NSStringFromClass(self.class);
- NSLog(@"classname %@", className);
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- Class class = [self class];
- // When swizzling a class method, use the following:
- // Class class = object_getClass((id)self);
- SEL originalSelector = @selector(viewWillAppear:);
- SEL swizzledSelector = @selector(xxx_viewWillAppear:);
- Method originalMethod = class_getInstanceMethod(class, originalSelector);
- Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
- BOOL didAddMethod =
- class_addMethod(class,
- originalSelector,
- method_getImplementation(swizzledMethod),
- method_getTypeEncoding(swizzledMethod));
- if (didAddMethod) {
- class_replaceMethod(class,
- swizzledSelector,
- method_getImplementation(originalMethod),
- method_getTypeEncoding(originalMethod));
- } else {
- method_exchangeImplementations(originalMethod, swizzledMethod);
- }
- });
- }
我们category重写了NSObject的 load 方法oc提供了objc/runtime.h类让我们获取这些东西,同时还提供了对类方法操作的函数
我们想的是,直接用一个方法替换掉系统的方法,然后把一些自定义的动作加到方法中
我们只想运行一次就够了,所以使用了 dispatch_once(&onceToken, ^{ …… }
接下来给类添加了新方法
把新方法和系统方法替换
- #pragma mark - Method Swizzling
- - (void)xxx_viewWillAppear:(BOOL)animated {
- NSLog(@"viewWillAppear: %@", self);
- [self xxx_viewWillAppear:animated];
- }
但是新方法实现的时候,调用的是 [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
Method Swizzle黑魔法,修改 ios 系统类库方法(转载)相关推荐
- 腾讯企业号 IOS 系统 调用方法 返回”wxLocalResource:/“问题
使用苹果手机和安卓手机进行上传,微信API 会返回值 serverID 然后把上传到微信临时服务器的图片 转移到 公司服务器,调用方法 临时的值 string tagUrl = "http ...
- 苹果屏蔽更新描述文件_屏蔽描述文件失效!iOS13屏蔽系统更新方法推荐
由于「iOS13屏蔽更新描述文件」过期失效了(iOS12.1以下版本不受影响),以至于很多之前安装了屏蔽系统更新的果粉用户今年又开始不断接受到系统推送弹窗提醒和后台自动下载更新固件的烦恼! 在之前的一 ...
- 修改android系统开机动画
本文转载自:http://blog.csdn.net/u012301841/article/details/51598115 修改android系统开机动画 转载于:https://www.cnblo ...
- iOS系统中应用程序间通信的方法及装置
申请号 :CN 201210548391 申请时间 : 2101.12.17 申请人 : 北京奇虎科技有限公司 [摘要] 本发明公开了iOS系统中应用程序间通信的方法及装置,用于在当前应用程序与目标应 ...
- 如何将高版本服务器系统转为低版本,iOS高版本备份恢复到低版本系统的方法
一般来说,在更新iOS系统的时候我们都会建议大家先用iTunes对系统进行完整备份.但时不时都会有人偷懒,或者使用手机OTA升级而没有对系统备份,最终导致不满意新系统了,想降级却无备份可以恢复的尴尬局 ...
- 如何在linux系统下修改mysql密码_如何在linux下修改mysql数据库密码?linux修改数据库密码的方法...
本篇文章给大家带来的内容是介绍如何在linux下修改mysql数据库密码?linux修改数据库密码的方法.有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助. Linux下修改Mysql的 ...
- 修改时间服务器失败,电脑系统同步时间失败怎么办 修改时间服务器的方法。...
一般来说,自己设定系统时间没有办法那么准确,因此更多的是利用时间同步功能,但是windows时间服务器不在中国,因此系统时间同步服务经常出错,那么如何解决系统时间同步出错的问题呢?下面给大家介绍修改电 ...
- ios android 内存不足,怎样解决手机内存不足?iOS系统可以试试这些方法
原标题:怎样解决手机内存不足?iOS系统可以试试这些方法 怎样解决手机内存不足?不管储存空间有多少GB,使用时间一长都会被满满的数据占据,有的时候甚至会出现储存空间不足的情况,怎么才能清理手机里的内存 ...
- 2021-01-27 CentOS系统将UTC时间修改为CST时间方法
CentOS系统将UTC时间修改为CST时间方法 世界协调时间(Universal Time Coordinated,UTC): GPS 系统中有两种时间区分,一为UTC,另一为LT(地方时)两者的区 ...
最新文章
- 【Java】泛型中 extends 和 super 的区别?
- Sql如何统计连续打卡天数
- ORA-06502:PL/SQL :numberic or value error: character string buffer too small
- Android中将一个图片切割成多个图片[转]
- C++11中的右值引用及move语义编程
- 吴恩达机器学习练习4:神经网络学习(反向传播)
- hdu 1285 确定比赛名次
- 强类型视图 后台拿不到数据_SAP开发-ABAP数据字典(视图)
- 青州市2021年高考成绩查询,2021年青州市高考状元名单资料,今年青州市高考状元多少分...
- 从数据库中获得表的字段和描述信息
- SQL Server 中位数、标准差、平均数
- 判断一个数字是整数还是小数
- atitit.团队建设--要不要招技术储备人才的问题
- 二级java考什么_​Java计算机二级考试考什么
- Java基础之==与equal()的区别
- 神经网络中矩阵求导术的应用
- GETWA_NOT_ASSIGNED
- tar 解压缩命令~
- 写给程序员的编程语言科普——前言
- Bellman-Ford algorithm
热门文章
- oracle学习笔记系列------oracle 基本操作之表的增删改查
- 进击的Objective-C--------Objective-C基础(-)
- CentOS6 下Vim安装和配置
- POJ 1521 Entropy
- [转]在资源管理器中使鼠标右键增加一个命令,运行cmd,同时使得当前路径为资源管理器当前的目录...
- OGR示例:写shp,求面与面的交和差操作
- true,false组合问题
- java能否调用com_java调用com
- e3是合法浮点数吗_下列哪些是不合法的浮点数的选项是 123 2e4.2 .e5 -e3 .234 1e3
- python define function的顺序_Python怎么根据一个函数来决定列表顺序