一、Runtime定义
Runtime(运行时)是一套由C、C++、汇编语言编写的API,他的作用是将数据类型由编译时推到了运行时,我们平时编写的OC代码,在程序运行的过程中都会被编译成Runtime的C语言代码。我们一般需要runtime来创建类和对象,进行消息传递,转发等。
二、Runtime特性
具有运行时的特性。
三、Runtime作用
- 可以动态的创建、添加类,修改这个类的属性和方法。
- 遍历一个类中的所有成员变量,属性,和方法。
- 用于消息的传递和转发等。
四、对象实质
在OC中对象 id被编译成objc_object。
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// object may have associated objects?
bool hasAssociatedObjects();
void setHasAssociatedObjects();
// object may be weakly referenced?
bool isWeaklyReferenced();
void setWeaklyReferenced_nolock();
// Optimized calls to retain/release methods
id retain();
void release();
id autorelease();
bool sidetable_isWeaklyReferenced();
void sidetable_setWeaklyReferenced_nolock();
(粘贴一小部分)
.......
}
里面包含很多的内容如:isa_t的共用体、isa操作、 弱引用、关联对象、内存管理等。
由此我们可以看出对象的本质是一个结构体。
五、那么Class是什么
1)找到NSObject.h
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
我们还知道NSObject是一个Class,看一下苹果是如何对类进行定义的。
typedef struct objc_class *Class;
/// Represents an instance of a class.
由此可知Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。
那我们来看一下objc_class
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
.......
}
类是继承于
objc_object的,所以我们也可以objc_class为类对象。
2)在oc中的runtime头文件中objc_class结构体中的定义如下:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
简单分析一下们长用的字段
isa:Class对象,指向objc_class结构体的指针,也就是这个Class的MetaClass(元类)- 类的实例对象的
isa指向该类;该类的isa指向该类的MetaClass。 MetaCalss的isa对象指向SuperMetaCalss(根元类)。- 如果
MetaClass是RootMetaCalss,那么该MetaClass的isa指针指向它自己。
- 类的实例对象的
super_class:Class对象指向父类对象- 如果该类的对象已经是
RootClass,那么这个super_class指向nil MetaCalss的SuperClass指向父类的MetaCalssMetaCalss是RootMetaCalss,那么该MetaClass的SuperClass指向该对象的RootClass
- 如果该类的对象已经是
一张常见的isa,super_class走位流程
ivars: 类中所有的属性列表。使用场景:我们在字典转换成模型的时候需要用到这个列表找到属性的名称,去取字典中的值,KVC赋值,或者直接Runtime赋值methodLists: 类中所有的方法列表。使用场景:如在程序中写好方法,通过外部获取到方法名称字符串,然后利用反射机制通过这个字符串得到方法,从而达到外部控制App已知方法。cache:缓存调用过的方法列表。调用方法的时候,会先从缓存中查找,如果没有在去方法列表中查找,从而提高运行效率。调用过的方法都会存到缓存中。protocols:该类遵循了哪些协议。
六、何时添加实例变量
能否向编译后的得到的类中增加实例变量?能否向运行时创建的类中增加实例变量?
- 不能向编译后的类中增加实例变量,因为一旦编译完成,类中的
instance_size已经确定,编译后的实例变量存储的ivars中,我们无法修改。 - 只要还没有注册到内存中,就可以添加。
- 可以在运行时添加属性和方法。
总结:
为什么我们总说OC是一门动态语言,因为OC对象都是基于RunTime实现的,由编译时推到了运行时。可以动态的创建、添加类,修改这个类的属性和方法。