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
地址值找到具体的代码实现,SEL
和IMP
是一一对应的,上面代码如果使用RunTime
应该怎么写?
要先导入头文件#import <objc/message.h>
,并且在Build Settings
中设置
这是因为自Xcode
5之后,🍎不建议使用底层函数,需要手动开启
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
中的NSClassFromString
,sel_registerName
相当于OC
中的NSSelectorFromString
其实也可以借助我们的Clang
编译器查看我们底层代码的实现
可以新建一个macOS
的命令行项目,在main.m
文件中依然调用上面代码,使用clang -rewrite-objc main.m
会生成一个main.cpp
文件,这个文件下会找到最终的实现代码
我们在objc/message.h
和objc/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);
具体到开发中,我们可以利用一些开放给我们的接口来实现相应的功能,下面列举几个案例
未完待续…
如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!
Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!
微信公众号OldDriverWeekly
,欢迎关注并提出宝贵意见
老司机iOS周报,欢迎关注或订阅
刚刚在线工作室,欢迎关注或提出建设性意见!
刚刚在线论坛, 欢迎踊跃提问或解答!
如有转载,请注明出处,谢谢!