要学习runtime,那就必须了解runtime是什么.runtime是运行时机制
什么是runtime?
1> runtime是一套底层的C语言API(包含很多强大实用的C语言数据类型、C语言函数)
2> 实际上,平时我们编写的OC代码,底层都是基于runtime实现的
- 也就是说,平时我们编写的OC代码,最终都是转成了底层的runtime代码(C语言代码)
既然要学习runtime,那肯定要知道runtime有什么用
runtime有啥用?
1> 能动态产生一个类、一个成员变量、一个方法
2> 能动态修改一个类、一个成员变量、一个方法
3> 能动态删除一个类、一个成员变量、一个方法
那么开发中怎么灵活的把runtime运用到我们的项目中呢?
首先我们需要导入头文件 #import<objc/runtime.h>
其次我们要熟悉runtime中的常用函数
Ivar * class_copyIvarList : 获得某个类内部的所有成员变量
Method * class_copyMethodList : 获得某个类内部的所有方法
Method class_getInstanceMethod : 获得某个实例方法(对象方法,减号-开头)
Method class_getClassMethod : 获得某个类方法(加号+开头)
method_exchangeImplementations : 交换2个方法的具体实现
import: <objc/message.h>消息机制
objc_msgSend(....)
下面写段个简单的代码,让大家感受一下runtime的强大
1-获取某个类中所有方法
+ (void)getInstanceMethodList
{
NSMutableString *methodStr = [NSMutableString string];
// 获取某个类中所有方法
// 获取某个类中所有方法
// Class:获取哪个类的方法
// outCount:类中方法总数
// class_copyMethodList:只能获取当前类
unsigned int count = 0;
// 获取Method数组
Method *methodList = class_copyMethodList(self, &count);
for (int i = 0; i < count; i++) {
// 获取方法
Method method = methodList[i];
// 获取方法名
SEL sel = method_getName(method);
[methodStr appendFormat:@"\n%@\n",NSStringFromSelector(sel)];
}
NSLog(@"%@",methodStr);
}
+ (void)getClassMethodList
{
NSMutableString *methodStr = [NSMutableString string];
// 获取某个类中所有方法
// 获取某个类中所有方法
// Class:获取哪个类的方法
// outCount:类中方法总数
// class_copyMethodList:只能获取当前类
unsigned int count = 0;
// 获取类对象类名
NSString *className = NSStringFromClass(self);
// OC -> C .UTF8String
// 获取元类
Class metaClass = objc_getMetaClass(className.UTF8String);
// 获取Method数组
Method *methodList = class_copyMethodList(metaClass, &count);
for (int i = 0; i < count; i++) {
// 获取方法
Method method = methodList[i];
// 获取方法名
SEL sel = method_getName(method);
[methodStr appendFormat:@"\n%@\n",NSStringFromSelector(sel)];
}
NSLog(@"%@",methodStr);
}
@end
2-动态的添加方法
//控制器中调用eat方法
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Person *p = [[Person alloc] init];
// performSelector:调用未声明方法
// [p performSelector:@selector(eat)];
[p performSelector:@selector(eat:) withObject:@"213"];
// _cmd:当前方法编号,viewDidLoad
// NSLog(@"%@ %@",self,NSStringFromSelector(_cmd));
}
内部实现
@implementation Person
// 定义test的函数,没有返回值,参数(id,SEL)
// void:v id:@ SEL->:
void test(id self,SEL _cmd, NSString *str)
{
NSLog(@"自己添加方法%@",str);
}
// 只要调用了一个未实现方法,就会调用这个方法进行处理
// sel:就是未实现方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// [@"eat" isEqualToString:NSStringFromSelector(sel)]
// 判断下是否是eat方法
if (sel == NSSelectorFromString(@"eat:")){
// 动态添加eat方法
// class:给哪个类添加方法
// SEL:添加哪个方法
// IMP:方法实现,函数名:函数入口
// types:添加的方法类型
class_addMethod(self, sel, (IMP)test, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
3.动态的添加属性
/*
给系统的类添加一个属性,就需要使用runtime,设置关联.
NSObject类添加属性
*/
- (void)setName:(NSString *)name
{
// 根本就没有成员变量保存
// _name = name;
// 设置关联
// 如何保存变量
// object:给哪个对象添加属性
// key:属性名称
// value:就是需要保存到对象中值
// policy:保存策略
objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{
// 获取关联
return objc_getAssociatedObject(self, "name");
// return _name;
}
runtime还有很多强大的方法,大家有兴趣可以自己慢慢摸索。这里就不再一一介绍了。