Runtime(三)方法交换

作者: 2d9cba783f86 | 来源:发表于2018-08-19 22:32 被阅读23次

Runtime(三)方法交换

在刚开始关注Runtime时, 不知道小伙伴们是否听过一种传说

RuntimeObjective-C黑魔法

它怎么就黑魔法了, 通过前两节的讲述, 并没有发现呀.
其实众说纷纭的黑魔法就是Runtime的另一项技能, 也是这篇文章要说的方法交换, 英文名MethodSwizzling

加载顺序

在说方法交换之前先科普一下, 加载顺序, 在我们项目target下的Build Phases->Compile Sources里都是项目内所有的.m文件, 这里的每一个.m文件在初始装载时都会调用一个类方法, +(void)load类方法, 这个可是默认加载的哦. 我们交换方法就是在这个类方法里进行交换.

方法交换实现原理

method_exchangeImplementations方法交换是用这个函数来实现的

/**
  @param m1 : 方法一
  @param m2 : 方法二 
 */
method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)

通过第一篇文章我们知道, Methodobjc_method结构体的指针, objc_method结构体中包含了SELIMP, 其中SEL是方法名称, IMP是方法的实现, 是指向函数体的函数指针, SELIMP是一一对应的, 而method_exchangeImplementations交换方法的原理 就是改变方法一方法二SELIMP的对应关系, 用一张图来表示
交换前:

屏幕快照 2018-08-19 下午9.59.37.png

交换后:


屏幕快照 2018-08-19 下午10.01.56.png

通过图片, 相信你看的更明白了, 通过方法交换特性, 将SEL 1的方法实现IMP 1SEL 2的方法实现IMP 2 进行交换了, 也就是说, 当我给对象消息让它执行SEL 1 消息时, 实际上执行的是IMP 2

原来如此, 那来看看代码吧

代码

接下来就通过代码, 为大家实现一个方法交换, 来交换一下UITableView-(void)reloadData方法, 当UITableView没有数据的时候, 显示一张没有更多数据的图片
UITableView写一个category

// .h
#import <UIKit/UIKit.h>

@interface UITableView (MethodSwizzling)

@end

// .m
#import "UITableView+MethodSwizzling.h"
#import <objc/runtime.h>

@implementation UITableView (MethodSwizzling)
//1. 在 load 类方法里进行方法交换
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //2. 获取reloadData Method
        // class_getInstanceMethod函数, 获取对象方法
        // class_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name)
        // 参数 cls: 获取方法对象的类
        // 参数 SEL: 获取的方法
        // 返回值:   返回 Method 用于 method_exchangeImplementations 进行方法交换
        Method reloadData = class_getInstanceMethod([self class], @selector(reloadData));
        //3. 获取要交换的my_reloadData 返回 Method 用于 方法交换
        Method my_reloadData = class_getInstanceMethod([self class], @selector(my_reloadData));
        //4. 方法交换
        method_exchangeImplementations(reloadData, my_reloadData);
    });
}

- (void)my_reloadData {
    // 由于方法已经交换, 此时进入[self my_reloadData];
    // 调用的是系统的 reloadData
    [self my_reloadData]; //5. 先更新数据
    //6. 如果当前tableView的cell行数为0时
    if (0 == self.visibleCells) {
    // 设置tableView的backgroundView为一张图片
        self.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"无数据背景图"]];
    } else {
    // 否则tableView的backgroundView背景图置为nil
        self.backgroundView = nil;
    }
}
@end
代码内函数讲解:

class_getInstanceMethod函数, 获取对象方法的函数, 与之对应的还有一个
class_getClassMethod函数, 用于获取类方法

// 参数一: Class, 获取方法的类
// 参数二: SEL,  方法名
// 返回值: Method
OBJC_EXPORT Method _Nullable
class_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name)

// 参数一: Class, 获取方法的类
// 参数二: SEL,  方法名
// 返回值: Method
OBJC_EXPORT Method _Nullable
class_getClassMethod(Class _Nullable cls, SEL _Nonnull name)

tableViewvisibleCells属性, 有的同学看它可能陌生

// visibleCells 是一个只读属性, 返回的是tableView 当前cell的数组
@property (nonatomic, readonly) NSArray<__kindof UITableViewCell *> *visibleCells;
注意:

方法交换应该在dispatch_once中完成, 由于方法交换改变了整个工程的状态, 所有的tableView调用reloadData方法都会进行交换, 确保在不同线程中也只执行一次

tableView没有数据时的效果

IMG_1516.PNG

看到了吗? 利用Runtime的方法交换, 我们可以解决开发中很常见的tableView刷新没有数据的问题, 没想到吧, 这样的效果竟然可以用方法交换来实现, 其实方法交换能实现的功能还有很多, 需要我们细心去发掘, 今天就为大家讲解这一个应用场景, 通过上面的代码原理还有枯燥的概念, Runtime方法交换, 你学会了吗?

相关文章

  • runtime

    runtime交换方法 动态添加方法

  • Runtime(三)方法交换

    Runtime(三)方法交换 在刚开始关注Runtime时, 不知道小伙伴们是否听过一种传说 Runtime是Ob...

  • runTime常用方法

    使用runTime改变实例成员的值 使用runtime来交换两个方法 注意再次调用该方法不交换 使用runTime...

  • Runtime

    runtime运行时机制1:通过runtime,实现方法交换(交换两个类方法、交换两个实例方法)2:通过runti...

  • Day3

    1 runtime运行时机制1:通过runtime,实现方法交换(交换两个类方法、交换两个实例方法)。2:通过ru...

  • runtime的理解(二)

    主要内容 利用 runtime 交换方法 利用 runtime 动态添加方法 利用 runtime 动态添加属性 ...

  • 查看SDK调用支付宝参数

    使用runtime 方法交换openurl

  • objc runtime (四)动态添加属性

    在《objc runtime (二)交换方法》中我提到过runtime最实用的就是交换方法和动态添加属性两个用法。...

  • iOS runtime如何交换两个类方法

    如有转载,请标明出处:iOS runtime如何交换两个类方法 runtime交换实例方法,老生常谈的问题,很多b...

  • iOS -- runtime的应用

    runtime主要有一下几种应用场景 方法交换 添加属性 (一)方法交换 (1)字体适配 方法交换实际交换的是方法...

网友评论

    本文标题:Runtime(三)方法交换

    本文链接:https://www.haomeiwen.com/subject/zjphiftx.html