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?

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

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

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

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

把新方法和系统方法替换

[objc] view plaincopyprint?

  1. #pragma mark - Method Swizzling
  2. - (void)xxx_viewWillAppear:(BOOL)animated {
  3. NSLog(@"viewWillAppear: %@", self);
  4. [self xxx_viewWillAppear:animated];
  5. }

但是新方法实现的时候,调用的是 [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

时间: 2024-11-19 09:35:06

Method Swizzle黑魔法,修改 ios 系统类库方法(转载)的相关文章

关于访问iOS系统通讯录方法。

一.在iOS中,有2个框架可以访问用户的通讯录: 1.AddressBookUI.framework>提供了系统自带联系人列表界面.联系人详情界面.添加联系人界面等.>一般用于选择联系人. 2.AddressBook.framework>纯C语言的API,仅仅是获得联系人数据.>没有提供UI界面展示,需要自己搭建联系人展示界面.>里面的数据类型大部分基于Core Foundation框架,使用较难. 二.但是从iOS6开始,需要得到用户的授权才能访问通讯录,因此在使用之前,需

ios系统能力&amp;api转载链接汇总

1.判断有无sim卡 http://www.2cto.com/kf/201306/223744.html 2.Let's Build xxx (如nsobject)系列- by Mike Ash,可以用做学习(理解很多ios内部的实现机制),很不错  https://www.mikeash.com/pyblog/friday-qa-2013-02-08-lets-build-key-value-coding.html 3.method swizz http://www.cocoachina.co

iOS 常用公共方法(转载至微信号:CocoaChinabbs)

1. 获取磁盘总空间大小 2. 获取磁盘可用空间大小 3. 获取指定路径下某个文件的大小 4. 获取文件夹下所有文件的大小 5. 获取字符串(或汉字)首字母 6. 将字符串数组按照元素首字母顺序进行排序分组 使用如下: 输出结果如下: 7. 获取当前时间 8. 计算上次日期距离现在多久, 如 xx 小时前.xx 分钟前等 使用如下: 输出结果如下: 9. 判断手机号码格式是否正确 10. 判断邮箱格式是否正确 11. 将十六进制颜色转换为 UIColor 对象 12. 对图片进行滤镜处理 13.

ios系统铃声调用方法

首先,这里我要说明这里并不是真正调用系统内部自带的铃声,因为苹果是不允许开发者调用的,没有给开发者接口:如果调用了就无法上线的!那为什么AppStore里面还有那么多app显示的效果是调用系统的铃声一样呢?为什么就能上线呢?其实不然,他们是使用了系统一样的铃声!也就说他们录制和系统铃声相似,然后包含进他们的bundle中来实现的. 所以,我们想要实现调用系统铃声的效果,只能通过这个途径:把音频文件捆绑经我们的bundle中来调用,播放! 给一个网址,里面好多苹果系统铃声(ios8的也有啦....

iOS系统网络抓包方法

在进行iOS开发过程中,经常会遇到各种各样的网络访问问题,以前苦于没有抓包工具,很多网络问题解决起来很痛苦.现在终于好了,本文提供两种方式进行网络抓包: 1. 网络共享 + 可视化抓包工具 基本原理 原理比较简单,ios设备通过代理方式共享连接mac电脑的无线网卡,使用抓包工具抓包,然后进行分析(我们推荐使用Wireshark,在MAC系统上也可以使用Paros工具). 现在以MAC系统下Paros工具为例,详细描述下抓包过程: 操作步骤 1)  首先将MAC电脑的以太网共享给airport,使

修改linux系统时间的方法(date命令)

修改linux系统时间的方法(date命令) 来源:互联网 作者:佚名 时间:11-18 23:22:27 [大 中 小] date命令不仅可以显示系统当前时间,还可以用它来修改系统时间,下面简单的介绍下,方便需要的朋友 命令格式为: date -s 时间字符串 例如只修改系统的日期,不修改时间(时分秒) date -s 2012-08-02 或只修改时间不修改日期 date -s 10:08:00 当然也可以同时修改日期和时间 date -s "2012-05-18 04:53:00"

教你Mac OS系统四种修改Hosts文件的方法

使用Mac OS X系统的用户,在某些时候可能遇到了需要修改系统Hosts文件的情况,那么Mac OS系统如何修改Hosts文件呢?和Windows系统有何区别呢?我们知道其实修改Hosts文件只需要在硬盘中找到该文件,再编辑修改就OK了,但是很多童鞋们发现只要编辑 Hosts 文件就出现"你不是文件 hosts 的所有者,因此没有权限写到该文件"的提示,要解决这个权限问题又比较麻烦,对于刚刚使用 Mac 的用户来说并不容易整明白. 因此,我们在这里搜集和整理了以下几个方法供大家使用,

iOS系统版本判断方法

在iOS系统中提供了系统版本的判断函数,因此我们可以很容易得到他的当前系统版本: [[UIDevice currentDevice] systemName];//系统名字[[UIDevice currentDevice] systemVersion];//系统版本号[[UIDevice currentDevice] uniqueIdentifier];//[[UIDevice currentDevice] model];  //设备型号 这些方法都能够帮助你快速得到你所想要的关于系统硬件和软件的

【学习ios之路:Objective-C】OC中常用的系统排序方法

①.OC中常用排序方法: 1).不可变数组 - (NSArray *)sortedArrayUsingSelector:(SEL)comparator; - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr; 2)可变数组 - (void)sortUsingSelector:(SEL)comparator; - (void)sortUsingComparator:(NSComparator)cmptr; 3).字典排序 - (NS