网上有很多对runtime机制的原理有很多介绍,这里不重复了。这里主要讲讲runtime如何使用,怎么用,我们可以用在哪些场景。
一般我们用Runtime都是想动态的修改或增加原来对象的属性和方法达到自己想要的结果。
那Object-C如何与Runtime进行交互的呢。有如下三种交互方式
1.Objective-C 源代码
比如我们发送这样一个[receiver message],实际上在运行时就会解析成objc_msgSend(id receiver, SEL selector);
2.NSObject类定义的方法(比如class返回对象的类;isKindOfClass:和isMemberOfClass:则检查对象是否在指定的类继承体系中;respondsToSelector:检查对象能否响应指定的消息;conformsToProtocol:检查对象是否实现了指定协议类的方法;methodForSelector:则返回指定方法实现的地址)
3.对 runtime 函数的直接调用
今天我们着重介绍对Runtime函数的直接调用。
既然要用Runtime的函数,我们就要首先介绍它的常用的API,本质上Runtime就是一系列C语言的API。
1).Class object_setClass(id obj, Class cls)/Class object_getClass(id obj) //更改对象的类/获取对象的类
- (void) setClassTest
{
NSError *err = [[NSError alloc] init];
Class aClass =object_setClass(err, [NSString class]);
NSLog(@"aClass:%@",NSStringFromClass(aClass));
NSLog(@"obj class:%@",NSStringFromClass([err class]));
}
打印结果:
aClass:NSError
obj class:NSString
可见已经动态改变了err这个对象的类
- (void) getClassTest
{
Class aLogClass =object_getClass(err);
NSLog(@"aLogClass %@",NSStringFromClass(aLogClass));
}
打印结果:aLogClass NSString
2).const char *object_getClassName(id obj) //获取对象的类名
- (void) getClassName
{
NSError *err = [[NSError alloc] init];
NSString *className = [NSString stringWithCString:object_getClassName(err) encoding:NSUTF8StringEncoding];
NSLog(@"className:%@", className);
}
3).Class objc_getClass(const char *name) // 通过名称查找到该类的定义
{
Class LenderClass = objc_getClass("NSError");
}
4).Class objc_getMetaClass(const char *name) //返回metaclass
关于这个MetaClass,这里着重讲一下
MetaClass是类对象的类。每个对象都有一个metaClass,这个Class主要存储类方法,就是以”+”开头的方法。
当你向一个类发送消息时,runtime会在这个类的meta-class的方法列表中查找。
再深入一下,meta-class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而基类的meta-class的isa指针是指向它自己。
借用网上的图表示一下。
红色圈起来的部分可见形成一个完美闭环。
讲到这里估计很多人已经有点晕了,所以这篇先结束,下面再以代码详解。