iOS 使用runtime动态添加方法

本文介绍如何使用Objective-C runtime动态为类添加方法,避免预先定义大量方法导致的内存消耗,通过实例演示如何为`Person`类添加`eat`、`run:`和`play:`方法,以及在实际场景中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用runtime 动态添加方法的应用场景:

  • 如果一个类方法非常多,加载类到内存的时候也比较耗费资源,需要给每个方法生成映射表,可以使用动态给某个类,添加方法解决。

代码展示

#import "Person.h"
#import <objc/runtime.h>

@implementation Person

//调用了一个未实现方法时一定会执行 resolveInstanceMethod:方法
+(BOOL)resolveInstanceMethod:(SEL)sel {
    // 判断方法名是不是eat
    if (sel == NSSelectorFromString(@"eat")) {
        /**
         class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
                         const char * _Nullable types)
         1、Class  cls: 给哪个类添加方法
         2、SEL name:添加什么方法(方法的名称)
         3、IMP imp:一个新方法的实现函数,函数至少有两个参数id self和SEL _cmd
         4、const char * _Nullable types: 方法类型
                  v  没有返回值
                  @ 对象 id
                  :  方法
         5、返回值: 方法添加成功,则返回 YES,否则返回 NO(例如:该类已包含具有该名称的方法实现)。
         */
        //使用runtime 动态添加 eat 方法
        //添加了一个无返回值无参数的方法
        // v@: 表示一个void类型的方法,无返回值
        class_addMethod(self, @selector(eat), (IMP)eat, "v@:");
     } 
      
     if (sel == NSSelectorFromString(@"run:")) { 
        //添加无返回值有参数的方法
        // v@: 后面的 @ 表示一个对象类型的参数(例中NSNumber类型)
        class_addMethod(self, @selector(run:), (IMP)run, "v@:@");
     } 
      
     if (sel == NSSelectorFromString(@"play:")) {  
        //添加有返回值有参数的方法
        class_addMethod(self, @selector(play:), (IMP)play, "@@:@");
   } 
    
    return [super resolveInstanceMethod:sel];
}

// eat 方法实现
      // self:方法调用者
      // _cmd:当前方法编号
    // 任何一个方法都能调用self,_cmd,其实任何一个方法都有这两个隐式参数
void eat(id self, SEL _cmd) {
    NSLog(@"吃东西");
}

// run:方法的实现
void run(id self, SEL _cmd, NSNumber *meter) {
    NSLog(@"跑了 %@ 米", meter);
}

// play: 方法的实现
//返回值是一个 NSString 类型的数据
NSString *play(id self, SEL _cmd, NSString *ball) {
    NSLog(@"踢足球 - %@",ball);
    return ball;
}
@end
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {        
      //创建 Person 对象
        Person *p = [[Person alloc]init];
        //由于Person类中没有声明eat方法,无法直接用p对象调用,所以通过performSelector执行我们动态添加的eat方法。(调用没有实现的 eat 方法)
        [p performSelector:@selector(eat)];
        [p performSelector:@selector(run:) withObject:@"100"];
        NSString *ball = [p performSelector:@selector(play:) withObject:@"footerball"];
        NSLog(@"ball = %@", ball);
    }
    return 0;
}
打印的值
2022-08-03 12:18:37.195178+0800 Runtime 的相关应用场景[98335:2156011] 吃东西
2022-08-03 12:18:37.195801+0800 Runtime 的相关应用场景[98335:2156011] 跑了 1002022-08-03 12:18:37.195926+0800 Runtime 的相关应用场景[98335:2156011] 踢足球 - footerball
2022-08-03 12:18:37.195998+0800 Runtime 的相关应用场景[98335:2156011] ball = footerball
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值