iOS开发 Method Swizzling

众所周知,我们UIKit中的 UIViewController类 有一个重要对象方法
- (void)viewWillAppear:(BOOL)animated;
苹果公司没有将其方法的实现源码开源, 假设我们想改变他的方法实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有其他方法吗?
那就是 Method Swizzling。

1. Method Swizzling 原理

在Objective-C中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现。
每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的Method实现。


1.png

我们可以利用
- OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
来交换2个方法中的IMP,
我们可以利用
- OBJC_EXPORT IMP method_setImplementation(Method m, IMP imp)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
来直接设置某个方法的IMP
............等等。
实际上就是,偷换了方法的IMP,如下图所示:


2.png

2.利用Method Swizzling 实现自己的 viewWillAppear方法。

第一步:给自己的UIViewController加自己的viewWillApper
第二步:调换IMP

 #import "UIViewController+Swizzling.h"
 #import <objc/runtime.h>

 @implementation UIViewController (Swizzling)
+ (void)load
{
Class class = [self class];

SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(myViewWillAppear:);

Method ori_Method =  class_getInstanceMethod(class, originalSelector);
Method my_Method = class_getInstanceMethod(class, swizzledSelector);
method_exchangeImplementations(ori_Method, my_Method);

  }

- (void)myViewWillAppear:(BOOL)animated{

[self myViewWillAppear:animated];

NSLog(@"viewWillAppear: %@", self);

  }

 @end

这个时候运行程序:此时在 + (void)load方法的实现里,交换了viewWillAppear:和myViewWillAppear:的实现。 程序中viewController在表面上是调用viewWillAppear:,实际上调用的myViewWillAppear:方法。这样也就实现了,myViewWillAppear:方法对ViewWillAppear:方法的拦截(就可以在myViewWillAppear:的实现里写一写关于埋点之类的代码...或等等...),接下来在myViewWillAppear:的实现代码里,调用 [self myViewWillAppear:animated];实际上是在调用ViewController的ViewWillAppear:方法。如果UIViewController子类如果不实现ViewWillAppear:则默认找其父类的ViewWillAppear:......以此类推直至找到UIViewController的ViewWillAppear:方法。。。UIViewController的ViewWillAppear:方法的具体实现是不开源的。

3.png

3.Method Swizzling 的封装。

第一步:创建NSObject的分类 NSObject+swizzling
第二步:在NSObject+swizzling.h声明自己的类方法,这里我暂时写四个方法...

+ (BOOL)overrideMethod:(SEL)originalSel withMethod:(SEL)swizzledSel;
+ (BOOL)exchangeMethod:(SEL) originalSel withMethod:(SEL) swizzledSel;
+ (BOOL)overrideClassMethod:(SEL) originalSel withClassMethod:(SEL) swizzledSel;
+ (BOOL)exchangeClassMethod:(SEL) originalSel withClassMethod:(SEL) swizzledSel;

第三步:在NSObject+swizzling.m实现自己的类方法:

+ (BOOL)overrideMethod:(SEL)originalSel withMethod:(SEL)swizzledSel
{
Method originalMethod =class_getInstanceMethod(self, originalSel);
if (!originalMethod) {
}

Method swizzledMethod =class_getInstanceMethod(self, swizzledSel);
if (!swizzledMethod) {
}

method_setImplementation(originalMethod, class_getMethodImplementation(self, swizzledSel));
return YES;
}

+ (BOOL)overrideClassMethod:(SEL)originalSel withClassMethod:(SEL)swizzledSel
 {
Class c = object_getClass((id)self);
return [c overrideMethod:originalSel withMethod:swizzledSel];
 }

+ (BOOL)exchangeMethod:(SEL)originalSel withMethod:(SEL)swizzledSel
{
Method originalMethod =class_getInstanceMethod(self, originalSel);
if (!originalMethod) {
}

Method swizzledMethod =class_getInstanceMethod(self, swizzledSel);
if (!swizzledMethod) {
}

method_exchangeImplementations(class_getInstanceMethod(self, originalSel),class_getInstanceMethod(self, swizzledSel));

return YES;
}

+ (BOOL)exchangeClassMethod:(SEL)originalSel withClassMethod:(SEL)swizzledSel
{
Class c = object_getClass((id)self);
return [c exchangeMethod:originalSel withMethod:swizzledSel];
}

晚安,好梦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 5,800评论 0 9
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 6,568评论 0 7
  • 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的...
    西木阅读 30,697评论 33 466
  • 继上Runtime梳理(四) 通过前面的学习,我们了解到Objective-C的动态特性:Objective-C不...
    小名一峰阅读 4,110评论 0 3
  • 目录 Objective-C Runtime到底是什么 Objective-C的元素认知 Runtime详解 应用...
    Ryan___阅读 5,913评论 1 3