Runtime库主要做下面几件事:
- 封装:在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
- 找出方法的最终执行代码:当程序执行[object doSomething]时,会向消息接收者(object)发送一条消息(doSomething),runtime会根据消息接收者是否能响应该消息而做出不同的反应。这将在后面详细介绍。
相关结构体声明
- Class
typedef struct objc_class *Class;
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
- objc_object 和 id
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
- objc_method
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}OBJC2_UNAVAILABLE;
- objc_ivar
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}OBJC2_UNAVAILABLE;
- objc_category
typedef struct objc_category *Category;
struct objc_category {
char *category_name OBJC2_UNAVAILABLE;
char *class_name OBJC2_UNAVAILABLE;
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE;
struct objc_method_list *class_methods OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
- objc_cache
typedef struct objc_cache *Cache OBJC2_UNAVAILABLE;
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method buckets[1] OBJC2_UNAVAILABLE;
};
Runtime类相关方法
获取类名,如果传入cls为Nil,则返回一个空字符串
const char* class_getName(Class cls);
获取类的父类,当cls为Nil或者cls为根类时,返回Nil。等同于NSObject的superClass方法。
Class class_getSuperClass(Class cls);
判断给定的Class是否是一个元类
BOOL class_isMetaClass(Class cls);
实例变量大小
size_t class_getInstanceSize(Class cls);
获取类中指定名称实例成员变量的信息,返回一个包含name指定成员变量信息的objc_ivar结构体指针。
Ivar class_getInstanceVariable(Class cls, const char* name);
获取类成员变量的信息,一般认为Objective-C不支持类变量。
Ivar class_getClassVariable(Class cls, const char* name);
添加成员变量,不支持在已存在的类中添加实例变量,因此不管是系统库提供的类还是我们自定义的类都无法动态添加成员变量。但是如果运行时创建类可以调用class_addIvar函数。而且只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。
BOOL class_addIvar(Class cls, const char* name, size_t size, uint8_t alignment, const char* types);
获取整个成员变量列表,不包含父类中声明的变量。
Ivar* class_copyIvarList(Class cls, unsigned int* outCount);
获取指定属性,同ivar。
objc_property_t class_getProperty(Class cls, const char* name);
获取属性列表
objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount);
为类添加属性
BOOL class_addProperty(Class cls, const char* name, const objc_property_attribute_t *attributes, unsigned int attributeCount);
替换类的属性
void class_replaceProperty(Class cls, const char* name, const objc_property_attribute_t *attributes, unsigned int attributeCount);
runtime提供了几个函数来确定一个对象的内存区域是否可以被垃圾回收器扫描,以处理strong/weak引用。
const uint8_t * class_getIvarLayout(Class cls);
void class_setIvarLayout(Class cls, const uint8_t *layout);
const uint8_t * class_getWeakIvarLayout(Class cls);
void class_setWeakIvarLayout(Class cls, const uint8_t *layout);
添加方法,会覆盖父类的方法实现,但不会取代本类中已存在的实现,如果本类中包含一个同名的实现,则函数会返回NO。如果要修改已存在实现,可以使用method_setImplementation。
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
获取实例方法,搜索父类的实现。
Method class_getInstanceMethod (Class cls, SEL name);
获取类方法,搜索父类的实现。
Method class_getClassMethod (Class cls, SEL name);
获取所有方法的数组,不会搜索父类的实现。
Method * class_copyMethodList (Class cls, unsigned int *outCount);
替代方法的实现,如果类中不存在name指定的方法,则类似于class_addMethod函数一样会添加方法;如果类中已存在name指定的方法,则类似于method_setImplementation一样替代原方法的实现。
IMP class_replaceMethod (Class cls, SEL name, IMP imp, const char *types);
返回方法的具体实现,该函数在向类实例发送消息时会被调用,并返回一个指向方法实现函数的指针。这个函数会比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函数指针可能是一个指向runtime内部的函数,而不一定是方法的实际实现。例如,如果类实例无法响应selector,则返回的函数指针将是运行时消息转发机制的一部分。
IMP class_getMethodImplementation (Class cls, SEL name);
IMP class_getMethodImplementation_stret (Class cls, SEL name);
类实例是否响应指定的selector,通常使用NSObject类的respondsToSelector:或instancesRespondToSelector:方法来达到相同目的。
BOOL class_respondsToSelector (Class cls, SEL sel);
添加协议
BOOL class_addProtocol ( Class cls, Protocol *protocol );
返回类是否实现指定的协议
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
返回类实现的协议列表,返回的是一个数组,在使用后我们需要使用free()手动释放。
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );
获取版本号
int class_getVersion ( Class cls );
设置版本号
void class_setVersion ( Class cls, int version );
动态创建一个新类和元类,如果我们要创建一个根类,则superclass指定为Nil。extraBytes通常指定为0,该参数是分配给类和元类对象尾部的索引ivars的字节数。
为了创建一个新类,我们需要调用objc_allocateClassPair。然后使用诸如class_addMethod,class_addIvar等函数来为新创建的类添加方法、实例变量和属性等。完成这些后,我们需要调用objc_registerClassPair函数来注册类,之后这个新类就可以在程序中使用了。
Class objc_allocateClassPair( Class cls, const char *name, size_t extraBytes );
销毁一个类及其相关联的类,用于销毁一个类,不过需要注意的是,如果程序运行中还存在类或其子类的实例,则不能调用针对类调用该方法。
void objc_disposeClassPair ( Class cls );
在应用中注册由objc_allocateClassPair创建的类
void objc_registerClassPair ( Class cls );
动态创建对象,创建实例时,会在默认的内存区域为类分配内存。extraBytes参数表示分配的额外字节数。这些额外的字节可用于存储在类定义中所定义的实例变量之外的实例变量。该函数在ARC环境下无法使用。
id class_createInstance ( Class cls, size_t extraBytes );
在指定位置创建类实例
id objc_constructInstance ( Class cls, void *bytes );
销毁类实例,但不会释放并移除任何与其相关的引用。慎用
void * objc_destructInstance ( id obj );
实例操作方法
- 针对整个对象进行操作的函数,这类函数包含
// 返回指定对象的一份拷贝
id object_copy ( id obj, size_t size );
// 释放指定对象占用的内存
id object_dispose ( id obj );
- 针对对象实例变量进行操作的函数,这类函数包含
// 修改类实例的实例变量的值
Ivar object_setInstanceVariable ( id obj, const char *name, void *value );
// 获取对象实例变量的值
Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue );
// 返回指向给定对象分配的任何额外字节的指针
void * object_getIndexedIvars ( id obj );
// 返回对象中实例变量的值
id object_getIvar ( id obj, Ivar ivar );
// 设置对象中实例变量的值
void object_setIvar ( id obj, Ivar ivar, id value );
- 针对对象的类进行操作的函数,这类函数包含
// 返回给定对象的类名
const char * object_getClassName ( id obj );
// 返回对象的类
Class object_getClass ( id obj );
// 设置对象的类
Class object_setClass ( id obj, Class cls );
获取类定义
获取已注册的类定义的列表,获取已注册的类定义的列表。我们不能假设从该函数中获取的类对象是继承自NSObject体系的,所以在这些类上调用方法是,都应该先检测一下这个方法是否在这个类中实现。
int objc_getClassList ( Class *buffer, int bufferCount );
创建并返回一个指向所有已注册类的指针列表
Class * objc_copyClassList ( unsigned int *outCount );
返回指定类的类定义,获取已注册的类定义的列表。我们不能假设从该函数中获取的类对象是继承自NSObject体系的,所以在这些类上调用方法是,都应该先检测一下这个方法是否在这个类中实现。
Class objc_lookUpClass ( const char *name );
Class objc_getClass ( const char *name );
Class objc_getRequiredClass ( const char *name );
返回指定类的元类,如果指定的类没有注册,则该函数会调用类处理回调,并再次确认类是否注册,如果确认未注册,再返回nil。不过,每个类定义都必须有一个有效的元类定义,所以这个函数总是会返回一个元类定义,不管它是否有效。
Class objc_getMetaClass ( const char *name );