博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS-动态添加方法
阅读量:4135 次
发布时间:2019-05-25

本文共 2235 字,大约阅读时间需要 7 分钟。

动态添加方法可以在动态创建的类中添加也可以在已存在的类中添加,先来看下动态添加方法的定义函数:

OBJC_EXPORT BOOLclass_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,                 const char * _Nullable types)     OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

函数分析:

参数1:Class 要向其添加方法的类;

参数2:SEL 指定要添加的方法的名称;
参数3:IMP 一个新方法的实现函数,函数至少有两个参数id selfSEL _cmd
参数4:types 描述方法参数类型的字符数组,;

返回值: 方法添加成功,则返回 YES,否则返回 NO(例如:该类已包含具有该名称的方法实现)。

我们以已经存在的类中添加方法为例,先创建一个Person类:

@interface Person : NSObject@end

先为Person类添加一个实例对象方法(减号方法):

Person *p = Person.new;BOOL isAdd = class_addMethod(Person.class, @selector(eat:), (IMP)EatFunction, "v@:@");[p performSelector:@selector(eat:) withObject:@"芒果"];// 带返回值写法// class_addMethod(Person.class, @selector(eat:), (IMP)EatFunction, "@@:@");// NSString *food = [p performSelector:@selector(eat:) withObject:@"芒果"];

v@: 表示一个void类型的方法,无返回值,后面一个@表示一个对象类型的参数(例中NSString类型);由于Person类中没有声明eat方法,无法直接用p对象调用,所以通过performSelector执行我们动态添加的eat方法。

void EatFunction( id self, SEL _cmd, NSString *food) {
NSLog(@"%@",food);}// 带返回值写法//NSString * EatFunction( id self, SEL _cmd, NSString *food) {
// NSLog(@"%@",food);// return food;//}

先为Person类添加一个类对象方法(加号方法):

,类对象方法是存储在该类对应的元类中的,所以添加类方法需要向元类中添加,获取元类的有两中方法:
1、通过objc_getMetaClass()函数,传入参数为C格式的类名称字符串,返回元类

OBJC_EXPORT Class _Nullableobjc_getMetaClass(const char * _Nonnull name)    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);

2、通过object_getClass()函数,注意这个函数既可以获取该类,也可以获取该类对应的元类,就看你传入的参数类型;当传入参数为Perosn类的实例对象即p时,返回的是该类;当传入的参数为Perosn类对象时,返回的就是Person类的元类

OBJC_EXPORT Class _Nullableobject_getClass(id _Nullable obj)     OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

注:虽然object_getClass()函数的参数是id(任意对象)类型,但是,所以可以把类对象当作参数。

添加方法时稍微有些变化:

class_addMethod(object_getClass(Person.class), @selector(eat:), (IMP)EatFunction, "v@:@");// 或者// BOOL isAdd = class_addMethod(objc_getMetaClass(NSStringFromClass(Person.class).UTF8String), @selector(eat:), (IMP)EatFunction, "v@:@");

执行方需要用Person去调用

[Person performSelector:@selector(eat:) withObject:@"黄瓜"];

有人会疑问performSelector:不是实例对象方法吗?为什么用类对象去调用也可以实现呢?还记得这张图吗?

在这里插入图片描述
元类中的superclass指针指向其父类对应的的元类,而根类(NSObject)的元类的superclass指针却指向的是根类的实例类(上图中间一排,普通类),所以当Person调用类方法时,如果Person类没有该方法,就会一级一级向父类的元类中找,如果找到根类的元类还是没有该类方法的实现,就向根类的普通类中去找相应的实例方法的实现,如果找到了也可以调用,如果还是没有程序就会Crash。

转载地址:http://pgivi.baihongyu.com/

你可能感兴趣的文章
js报错显示subString/subStr is not a function
查看>>
高德地图js API实现鼠标悬浮于点标记时弹出信息窗体显示详情,点击点标记放大地图操作
查看>>
初始化VUE项目报错
查看>>
vue项目使用安装sass
查看>>
HTTP和HttpServletRequest 要点
查看>>
在osg场景中使用GLSL语言——一个例子
查看>>
关于无线PCB中 中50欧姆的特性阻抗的注意事项
查看>>
Spring的单例模式源码小窥
查看>>
后台服务的变慢排查思路(轻量级应用服务器中测试)
查看>>
MySQL中InnoDB事务的默认隔离级别测试
查看>>
微服务的注册与发现
查看>>
bash: service: command not found
查看>>
linux Crontab 使用 --定时任务
查看>>
shell编程----目录操作(文件夹)
查看>>
机器学习-----K近邻算法
查看>>
HBASE安装和简单测试
查看>>
关于程序员的59条搞笑但却真实无比的编程语录
查看>>
搞笑--一篇有趣的文章编译自一篇西班牙博客。有一位美丽的公主,被关押在一个城堡中最高的塔上,一条凶恶的巨龙看守着她,需要有一位勇士营救她…
查看>>
非常不错 Hadoop 的HDFS (Hadoop集群(第8期)_HDFS初探之旅)
查看>>
Tomcat启动错误,端口占用
查看>>