iOS开发- Runtime的两种方法

一、介绍:

系统中SEL(方法编号)与IMP(方法实现)是一对一的映射关系,方法交换的中心思想是对SEL与IMP进行处理。由此可见有两种方案:

  1. 交换SEL,使系统SEL对应新的方法的IMP。
  2. 交换IMP,使新的方法IMP对应系统方法的SEL。

二、上代码:

2.1 交换SEL

1)首先对需要用到的方法进行简单说明:

a. 根据方法编号从类中取出方法:

@param cls      获取方法类
@param name 方法编号 

class_getClassMethod(Class _Nullable cls, SEL _Nonnull name) - 取出类方法
class_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name) -取出实例方法
b.交换SEL

@param m1    系统方法
@param m2   新方法

method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)  
c.给类动态添加方法

@param cls    需要添加方法的类
@param SEL  添加的方法编号
@param IMP  添加的方法的实现
@param types  对新方法的返回值及参数类型做的标识

class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types) 

2)应用场景:

需求如下:在调用以下系统方法的时候,对URLString进行校验,判断是否为nil,并提示输出。

  • (nullable instancetype)URLWithString:(NSString *)URLString;

第一种方法:创建一个NSURL的分类,在分类中创建新的类方法,在load方法中进行方法的交换。

创建分类:NSURL+HookUrl

#import "NSURL+HookUrl.h"
#import <objc/message.h>
#import <objc/runtime.h>

@implementation NSURL (HookUrl)

+(void)load{
    
    Method m1 = class_getClassMethod(self, @selector(URLWithString:)); - 系统方法
    
    Method m2 = class_getClassMethod(self, @selector(HKURLWithString:));-新方法
    
    method_exchangeImplementations(m1, m2);-交换
    
}

+ (nullable instancetype)HKURLWithString:(NSString *)URLString{
    // 因为进行了方法的交换,所以HKURLWithString对应的IMP是原系统方法实现。若使用URLWithString,会形成递归。
    
    NSURL *url = [NSURL HKURLWithString:URLString];
    
    if (url == nil) {
        
        NSLog(@"DDDDD");
    }
    
    return url ;
    
}

@end

第二种方法:创建一个hook类,进行方法的交换。

@implementation Hook

+(void)load{
    
  Method m1 = class_getClassMethod(NSURL.class, @selector(URLWithString:)); - 系统方法

 class_addMethod(object_getClass(NSURL.class), @selector(HKURLWithString:), (IMP)newMethod,"@@:@"); // 添加的是类方法

 //交换: SEL - IMP 映射
method_exchangeImplementations(m1, class_getClassMethod(NSURL.class, @selector(HKURLWithString:)));
    
}

void * newMethod(id self,SEL _cmd, NSString *str){

    NSURL *url = [[NSURL class] performSelector:@selector(HKURLWithString:) withObject:str];

    if (url == nil) {

       NSLog(@"DDDDD");
    }

    return (__bridge void *)(url) ;
    
}

2.2 交换IMP

1)首先对需要用到的方法进行简单说明:

更改IMP

@param m     方法
@param name  imp 方法实现 

method_setImplementation(Method _Nonnull m, IMP _Nonnull imp) 

2)应用场景:

需求如下:在调用以下系统方法的时候,对URLString进行校验,判断是否为nil,并提示输出。

  • (nullable instancetype)URLWithString:(NSString *)URLString;
@implementation Hook

+(void)load{
 
    Method m1 = class_getClassMethod(NSURL.class, @selector(URLWithString:));- 系统方法
    
    IMP swizzledMethod =(IMP)newMethod;-新的方法实现
    
    IMP methodImp = [NSURL.class methodForSelector:@selector(URLWithString:)];-系统方法的实现
    
    class_addMethod(object_getClass(NSURL.class), @selector(HKURLWithString:), swizzledMethod,"@@:@"); - 添加新方法到NSURL类
    
    Method m2 = class_getClassMethod(NSURL.class, @selector(HKURLWithString:)); - 获取新方法
    
    method_setImplementation(m1,swizzledMethod);
    method_setImplementation(m2,methodImp);
    - 交换IMP
}

void * newMethod(id self,SEL _cmd, NSString *str){

    NSURL *url = [[NSURL class] performSelector:@selector(HKURLWithString:) withObject:str];

    if (url == nil) {

       NSLog(@"DDDDD");
    }

    return (__bridge void *)(url) ;
    
}
                                                                  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值