RunTime探究


RunTime,即运行时,是基于C语言的一套API, 也被称为iOS系统的黑魔法,在开发中占据举足轻重的作用

这里以objc_msgSend即消息发送,作为切入点

新建一个项目

控制器中调用Person方法

Person * p = [[Person alloc] init];
[p eat];

当然还可以写成

Person * p = [Person alloc];
p = [p init];
[p performSelector:@selector(eat)];

OC中调用方法,其实就是向调用对象发送消息,即iOS的消息机制,每个对象中其实都有一张映射表,这里的@selector其实是方法标识SEL,根据这个方法标识会找到方法实现的指针,即IMP,再根据IMP地址值找到具体的代码实现,SELIMP是一一对应的,上面代码如果使用RunTime应该怎么写?

要先导入头文件#import <objc/message.h>,并且在Build Settings中设置

这是因为自Xcode5之后,🍎不建议使用底层函数,需要手动开启

Person *p = objc_msgSend(Person.class, @selector(alloc));
p = objc_msgSend(p, @selector(init));
objc_msgSend(p, @selector(eat));

这么写其实还可以再深入一点

Person *p = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));
p = objc_msgSend(p, sel_registerName("init"));
objc_msgSend(p, sel_registerName("eat"));

objc_getClass其实就相当于OC中的NSClassFromStringsel_registerName相当于OC中的NSSelectorFromString

其实也可以借助我们的Clang编译器查看我们底层代码的实现

可以新建一个macOS的命令行项目,在main.m文件中依然调用上面代码,使用clang -rewrite-objc main.m会生成一个main.cpp文件,这个文件下会找到最终的实现代码

我们在objc/message.hobjc/runtime文件中可以看到,系统给我们提供了众多接口,下面列举部分,仅做记录使用

// 获取实例对象的所属的类
Class object_getClass(id obj);

// 设置实例对象的所属的类
Class object_setClass(id obj, Class cls);

// 获取实例对象的所属类的类名
const char *object_getClassName(id obj);

// 返回指向给定对象分配的任何额外字节的指针
void *object_getIndexedIvars(id obj);

// 获取实例对象的成员变量
id object_getIvar(id obj, Ivar ivar);

// 设置实例对象的成员变量
 void object_setIvar(id obj, Ivar ivar, id value);

// 修改类实例的实例变量的值
Ivar object_setInstanceVariable(id obj, const char *name, void     *value);

// 获取对象实例变量的值
Ivar object_getInstanceVariable(id obj, const char *name, void     **outValue);

// 返回指定类的元类
id objc_getMetaClass(const char *name);

// 返回指定类的类定义
id objc_lookUpClass(const char *name);

// 返回实例对象的类
id objc_getClass(const char *name);

// 获取已注册的类定义的列表
int objc_getClassList(Class *buffer, int bufferCount);

// 创建并返回一个指向所有已注册类的指针列表
Class *objc_copyClassList(unsigned int *outCount);

// 获取类的类名
const char *class_getName(Class cls);

// 是否是元类
BOOL class_isMetaClass(Class cls);

// 获取类的父类
Class class_getSuperclass(Class cls);

// 设置新类的父类
Class class_setSuperclass(Class cls, Class newSuper);

// 类的版本信息
int class_getVersion(Class cls);

// 设置类的版本信息
void class_setVersion(Class cls, int version);

// 获取该类实例对象大小
size_t class_getInstanceSize(Class cls);

// 获取类中指定名称实例对象的信息
Ivar class_getInstanceVariable(Class cls, const char *name);

// 获取类成员变量的信息
Ivar class_getClassVariable(Class cls, const char *name);

// 获取整个成员变量列表
Ivar *class_copyIvarList(Class cls, unsigned int *outCount);

// 获取实例方法.
Method class_getInstanceMethod(Class cls, SEL name);

// 获取类方法.
Method class_getClassMethod(Class cls, SEL name);

// 返回方法的具体实现
IMP class_getMethodImplementation(Class cls, SEL name);

// 返回方法的具体实现
IMP class_getMethodImplementation_stret(Class cls, SEL name);

// 检查类是否响应指定的消息.
BOOL class_respondsToSelector(Class cls, SEL sel);

// 获取类方法列表.
Method *class_copyMethodList(Class cls, unsigned int *outCount);

// 检查类是否实现了指定协议类的方法.
BOOL class_conformsToProtocol(Class cls, Protocol *protocol);

// 返回类遵守的协议列表.
Protocol * __unsafe_unretained *class_copyProtocolList(Class cls,     unsigned int *outCount);

// 获取指定的属性
objc_property_t class_getProperty(Class cls, const char *name);

// 获取属性列表
objc_property_t *class_copyPropertyList(Class cls, unsigned int     *outCount);

// 创建实例对象
id class_createInstance(Class cls, size_t extraBytes);

// 在指定位置创建类实例
id objc_constructInstance(Class cls, void *bytes);

// 销毁类实例
void *objc_destructInstance(id obj);

// 创建一个新类和元类  (ClassPair:包含类和元类)
Class objc_allocateClassPair(Class superclass, const char *name,     size_t extraBytes);

// 在应用中注册由objc_allocateClassPair创建的类
void objc_registerClassPair(Class cls);

// 复制一份类
Class objc_duplicateClass(Class original, const char *name,size_t     extraBytes);

// 销毁一个类及其相关联的类
void objc_disposeClassPair(Class cls);

// 添加某个类的方法
BOOL class_addMethod(Class cls, SEL name, IMP imp,const char         *types);

// 替换某个类的方法
IMP class_replaceMethod(Class cls, SEL name, IMP imp,const char     *types);

// 添加某个类的变量,这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用
BOOL class_addIvar(Class cls, const char *name, size_t size,         uint8_t alignment, const char *types);

// 添加某个类的协议
BOOL class_addProtocol(Class cls, Protocol *protocol);

// 添加某个类的属性
 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);

// 通过方法名返回方法
SEL method_getName(Method m);

// 获取方法的实现地址
IMP method_getImplementation(Method m);

// 获取方法参数列表
unsigned int method_getNumberOfArguments(Method m);

// 修改方法实现
IMP method_setImplementation(Method m, IMP imp) ;

// 方法交换
void method_exchangeImplementations(Method m1, Method m2) ;

// 运行时给分类添加/删除属性
void objc_setAssociatedObject(id object, const void *key, id     value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, const void *key);
void objc_removeAssociatedObjects(id object);

具体到开发中,我们可以利用一些开放给我们的接口来实现相应的功能,下面列举几个案例

未完待续…

RunTimeDemo下载


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

本站总访问量 本文总阅读量