Runtime 一一 runtime使用-动态添加方法和属性

一、动态添加方法

应用场景: 当一个类的方法非常多,加载类到内存的时候比较耗资源,需要给每个方法生成映射表. 此时可以动态给某个类添加方法

面试题: 是否使用过performSelector, 其实就是想问你有没有动态添加过方法

知识点:

1. 所有的方法,默认都有 id self, SEL _cmd 这两个隐式参数. _cmd表示当前方法的方法编号

2. + (BOOL)resolveInstanceMethod:(SEL)sel 用来判断,未实现的方法是否是我们想要动态添加的方法

3. 动态添加 class_addMethod(arg1, arg2, arg3, arg4);

#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

/*
    动态添加方法:
    开发中的使用场景: 如果一个类方法非常多,加载类到内存的时候比较消耗资源,需要给每个方法生成映射表,可以动态给某个类添加方法
    面试题: 是否使用过performSelector, 其实主要想问你有没有动态添加过方法
 */

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Person *p = [[Person alloc] init];
//    [p performSelector:@selector(eat)];
    [p performSelector:@selector(run:) withObject:@"ZY" withObject:@20];
    
}

@end
#import "Person.h"
#import <objc/message.h>

@implementation Person

// 所有的方法.默认都有self, _cmd 这两个隐式参数
// _cmd 表示当前方法的方法编号
void eatFood(id self, SEL _cmd)
{
    NSLog(@"吃食物!");
}

void runPace(id self, SEL _cmd, NSString *name, NSNumber *meter)
{
    NSLog(@"我叫%@,我今年%@,我在?",name,meter);
    // _cmd 表示当前方法的方法编号
    NSLog(@"%@",NSStringFromSelector(_cmd));
}

// 当一个对象调用未实现的方法,会调用这个方法来处理,并且会把对应的方法列表传过来
// 可以用来判断,未实现的方法是否是我们想要动态添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
//    if ([NSStringFromSelector(sel) isEqualToString:@"eat"]){
    if (sel == NSSelectorFromString(@"eat")) {
        /*
         param1: class 给哪个类添加方法
         param2: SEL 添加哪个方法
         param3: IMP: 方法实现(在方法区) => 函数 => 函数入口 => 函数名
         param4: type: 方法类型
         */
        class_addMethod(self, sel, (IMP)eatFood, "v@:");
        
        return YES;
    }
    if ([NSStringFromSelector(sel) isEqualToString:@"run:"]) {
        
        class_addMethod(self, sel, (IMP)runPace, "v@:@@");
        
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
二、动态添加属性

应用场景: 给系统的类增加属性的时候,可以使用runtime动态添加属性.

本质: 动态添加属性,就是让某个属性与对象产生关联

runtime一般针对系统的类

需求: 把基类NSObject类,添加一个name字符串属性

步骤:

1. 给系统自带的NSObject属性添加分类

2. 在分类中声明name属性,在分类中@property NSString *name; 只会生成get,set方法的声明,并且不会生成私有属性_name.

本质不会生成成员属性,而是提供get,set方法声明,供外界调用

3. 在分类中实现get,set方法

4. set方法实现,把传递的值给对象关联

5. get方法实现,把关联的值取出来传出去

#import "ViewController.h"
#import "NSObject+Property.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

// 动态添加属性
// 开发场景:
// 给系统的类添加属性的时候,可以使用runtime动态添加属性方法
// 本质:动态添加属性,就是让某个属性与对象产生关联
// runtime一般都是针对系统的类

/*
    需求:让一个NSObject类 保存一个name字符串属性
    动态添加NSObject属性的步骤
    1.给系统自带的NSObject添加分类
    2.在分类中声明属性的get,set方法,本质并不是真的生成成员属性,而是提供get,set方法,供外界获取
    3.在分类实现get,set方法
    4.set方法实现,把传递的值给对象关联。
    5.get方法实现,把关联的值取出来传出去
 */

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSObject *objc = [[NSObject alloc] init];
    objc.name = @"ZY";
    NSLog(@"%@",objc.name);
    
    Person *p = [[Person alloc] init];
    p.name = @"GZY";
    
}
@end
分类NSObject+Property:

#import <Foundation/Foundation.h>

@interface NSObject (Property)

// @property分类: 只会生成get,set方法声明,不会生成方法实现,并且不会生成_name私有属性
@property NSString *name;

@end

#import "NSObject+Property.h"
#import <objc/message.h>

@implementation NSObject (Property)

// 属性名称
static const char *key = "name";

// set方法
- (void)setName:(NSString *)name
{
    // 让这个字符串与当前对象产生联系
    /*
     param1:object:给哪个对象添加属性
     param2:key:属性名称
     param3:value:属性值
     param4:policy:保存策略
     */
    objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

// get 方法
- (NSString *)name
{
    return objc_getAssociatedObject(self, key);
}

@end

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

white camel

感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值