美文网首页程序员
iOS 封装runtime库,一句话可实现方法交换

iOS 封装runtime库,一句话可实现方法交换

作者: Allan_野草 | 来源:发表于2020-08-03 11:17 被阅读0次

长话短说,直接上代码比较直观:

[CCRuntime exchangeMethod:[self class] name:@"viewWillAppear:" withBlock:^void(id _self, BOOL animated) {
    NSLog(@"已经被hook了");
    
    // 原来的方法实现会被交换至新的方法,方法名可通过下面获取
  
    // 回调原来viewWillAppear里面的代码
    [_self performSelector:NSSelectorFromString([CCRuntime exchangeOriginMethodUsingSelectorName:@"viewWillAppear:"]) withObject:@(animated)];
}];

至此,viewWillAppear已经成功被替换掉了。在回调viewWillAppear之前,会先执行打印代码。

如何实现?

我把原方法的实现替换成block,原方法的实现丢到一个新的方法。新的方法名可获取,有需要再回调即可。点击下载源码

其它介绍

除了方法交换之处,我还提供了其它API,提供更为便携地通过runtime操作方法、类、属性:

方法

一、为类动态添加一个方法,用block去构造方法实现:

[CCRuntime addMethodTo:[self class] name:@"getUserName:" withBlock:^int(id _self, int *userId){
    NSLog(@"userId是:%d", userId);
    return @"Allan";
} returnType:@"id" paramTypes:@[@"int"]];

二、为类动态添加一个方法,用已有方法去构造方法实现:

[CCRuntime addMethodTo:[self class] name:@"bar" from:[self class] name:@"foo"];

[self performSelector:NSSelectorFromString(@"bar")]; /* 打印:我是foo */

-(void)foo {
    NSLog(@"我是foo");
}

三、重置一个方法的实现,用block重置

[CCRuntime resetMethod:[self class] name:@"foo" withBlock:^{
    NSLog(@"我不是foo了呀");
}];
[self foo]; /* 打印:我不是foo了呀 */

四、交换一个方法,这个方法会以block作为方法实现:

[CCRuntime exchangeMethod:[self class] name:@"viewWillAppear:" withBlock:^void(id _self, BOOL animated) {
    NSLog(@"已经被hook了");
    
    // 原来的方法实现会被交换至新的方法,方法名可通过下面获取
  
    // 回调原来viewWillAppear里面的代码
    [_self performSelector:NSSelectorFromString([CCRuntime exchangeOriginMethodUsingSelectorName:@"viewWillAppear:"]) withObject:@(animated)];
}];

在之前,我们进行方法交换的一般做法是:多写一个方法,然后在初始化时用runtime库交换实现。

现在可以优雅地聚合代码和快速实现需求了。

属性

获取属性列表:

NSArray *props = [CCRuntime getPropertyListOnlyName:[self class]];

为对象属性添加动态属性:

UIViewController *vc = [UIViewController new];

/* 类似分类添加属性的做法,好处是不必再多写一个分类文件 */
[CCRuntime setObject:vc copyValue:@"广州" forKey:@"address"];

NSLog(@"address是:%@", [CCRuntime object:vc valueForKey:@"address"]);

动态创建一个类:

Class cls = [CCRuntime buildClass:[UIViewController class] name:@"TestViewController" ivarAndMethodBulider:^(Class  _Nonnull __unsafe_unretained cls) {
    // 可在block里面添加成员变量&方法
    [CCRuntime addIvar:cls name:@"name"];
    [CCRuntime addMethodTo:cls name:@"test" withBlock:^{
        NSLog(@"i am test控制器的方法");
    } returnType:@"void" paramTypes:@[]];
}];


UIViewController *vc = (UIViewController *)[CCRuntime getClassInstance:cls];

// 1.测试下成员变量
[CCRuntime setIvarValue:vc name:@"name" value:@"i am test控制器"];
NSLog(@"%@", [CCRuntime getIvarValue:vc name:@"name"]);

// 2.测试下方法
[vc performSelector:NSSelectorFromString(@"test")];

// 3.尝试下present刚才动态创建的类
vc.view.backgroundColor = [UIColor cyanColor];
[self presentViewController:vc animated:YES completion:nil];

相关文章

  • iOS 封装runtime库,一句话可实现方法交换

    长话短说,直接上代码比较直观: 至此,viewWillAppear已经成功被替换掉了。在回调viewWillApp...

  • iOS 按钮防止多次快速点击

    iOS 按钮防止多次快速点击,利用runtime交换方法,实现时间控制。

  • iOS 按钮防止多次快速点击

    使用runtime iOS 按钮防止多次快速点击,利用runtime交换方法,实现时间控制。 #import NS...

  • iOS:runtime实现方法交换

    新建一个类别,导入#import 在+ (void)load方法中写代码 至于具体...

  • iOS 黑魔法 Runtime Method Swizzling

    目录 1、直接使用 Runtime 方法交换开发的风险有哪些?RSSwizzle库也是方法交换库 https://...

  • RunTime实现

    1:RunTiem交换方法实现 //runTime交换方法实现 // 1,创建已有类的分类,并且实现自己的方...

  • Runtime

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

  • iOS - RunTime(Swift)

    RunTime实现存储属性(本质也是一个计算属性) RunTime实现方法交换

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

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

  • Day3

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

网友评论

    本文标题:iOS 封装runtime库,一句话可实现方法交换

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