问题
1.runtime 个人理解
2.runtime 常用api
3.runtime 日常运用解决问题
4.runtime 常用代码演练
答案
1.runtime 个人理解
1.OC是一门动态性比较强的编程语言,允许很多操作推迟到运行时在进行
2.OC的动态性就是有
3.平时编写的OC代码,底层都是转化成了 runtime api 进行调用
2.runtime 常用api
1.objc_xxx系列函数(关注于宏观使⽤,例如类与协议的空间分配、注册、注销等操作)
objc_getClass(const char * _Nonnull name) //获取Class对象
objc_getMetaClass //获取MetalClass对象
objc_allocateClassPair 分配空间,创建类(仅在创建之后,注册之前,能够添加成员变量)
objc_registerClassPair 注册⼀个类(注册后⽅可使⽤该类创建对象)
objc_disposeClassPair 注销某个类
objc_allocateProtocol 开辟空间创建协议
objc_registerProtocol 注册⼀个协议
objc_constructInstance 构造⼀个实例对象(ARC下⽆效)
objc_destructInstance 析构⼀个实例对象(ARC下⽆效)
objc_setAssociatedObject 为实例对象关联对象
objc_getAssociatedObject 获取实例对象的关联对象
objc_removeAssociatedObject 清空实例对象的所有关联对象
objc_msgSend 发送Objc消息
2.class_xxx系列函数(关注于类的内部,例如实例变量、属性、⽅法、协议等相关问题)
class_assIvar 为类添加实例变量
class_addProperty 为类添加属性
class_addMethod 为类添加⽅法
class_addProtocol 为类遵循协议
class_replaceMethod 替换类某⽅法的实现
class_getName 获取类名
class_isMetaClass 判断是否为元类
objc_getProtocol 获取某个协议
objc_copyProtocolList 拷⻉在运⾏时中注册过的协议列表
class_getSuperClass 获取某类的⽗类
class_setSuperClass 设置某类的⽗类
class_getProperty 获取某类的属性
class_getInstanceVariable 获取实例变量
class_getClassVariable 获取类变量
class_getInstanceMethod 获取实例⽅法
class_getClassMethod 获取类⽅法
class_getmethodImplementation 获取⽅法的实现
class_getInstanceSize 判断类是否实现某⽅法
class_respondsToSelector 判断类是否遵循某些以
class_createInstance 创建类的实例
class_copyIvarList 拷⻉类的实例变量列表
class_copyMethodList 拷⻉类的⽅法列表
class_copyProtocolList 拷⻉类遵循的协议列表
class_copyPropertyList 拷⻉类的属性列表
3.object_xxx系列函数(关注于对象的⻆度,例如实例变量)
object_copy 对象copy(ARC⽆效)
object_dispose 对象释放(ARC⽆效)
object_getClassName 获取对象的类名
object_getClass 获取对象的Class
object_setClass 设置对象的Class
object_getIvar 获取对象中实例变量的值
object_setIvar 设置对象中实例变量的值
object_getInstanceVariable 获取对象中实例变量的值(ARC中⽆效)
object_setInstanceVariable 设置对象中实例变量的值(ARC中⽆效)
4.method_xxx系列函数(关注于⽅法内部,例如⽅法的参数以及返回值类型和⽅法的实现)
method_getName 获取⽅法名
method_getImplementation 获取⽅法的实现
method_getTypeEncoding 获取⽅法的类型编码
method_getNumberOfArguments 获取⽅法的参数个数
method_copyReturnType 拷⻉⽅法的返回类型
method_getReturnType 获取⽅法的返回类型
method_copyArgumentType 拷⻉⽅法的参数类型
method_getArgumentType 获取⽅法的参数类型
method_getDescription 获取⽅法的描述
method_setImplementation 设置⽅法的实现
method_exchangeImplementations 替换⽅法的实现
5.property_xxx系列函数(关注于属性内部,例如属性的特性等)
property_getName 获取属性名
property_getAttributes 获取属性的特性列表
property_copyAttributeList 拷⻉属性的特性列表
property_copyAttributeValue 拷⻉属性中某特性的值
6.protocol_xxx系列函数(与协议相关)
protocol_conformsToProtocol 判断⼀个协议是否遵循另⼀个协议
protocol_isEqual 判断两个协议是否⼀致
protocol_getName 获取协议名称
protocol_copyPropertyList 拷⻉协议的属性列表
ptotocol_copyProtocolList 拷⻉某协议所遵循的协议列表
protocol_copyMethodDescriptionList 拷⻉协议的⽅法列表
protocol_addProtocol 为⼀个协议遵循另⼀个协议
protocol_addProperty 为协议添加属性
protocol_getProperty 获取协议中的某个属性
protocol_addMethodDescription 为协议添加⽅法描述
protocol_getMethodDescription 获取协议中某⽅法的描述
7.ivar_xxx系列函数(与实例变量相关)
ivar_getName 获取ivar名称
ivar_getTypeEncoding 获取类型编码
ivar_getOffset 获取偏移量
8.sel_xxx系列函数(讨论关于⽅法编号相关)
sel_getName 获取名称
sel_getUid 注册⽅法
sel_registerName 注册⽅法
sel_isEqual 判断⽅法是否相等
3.runtime 日常运用解决问题=
1.利用关联对象给 分类添加属性
2.遍历类的所有成员变量(修改textField的占位符颜色等,字典转模型,自动归档解档)
3.利用消息转发机制解决找不到方法奔溃问题
4.runtime 常用代码演练
1.简单的字典转模型
+ (instancetype)fan_objectWithJson:(NSDictionary *)json
{
id obj = [[self alloc] init];
unsigned int count;
Ivar *ivars = class_copyIvarList(self, &count);
for (int i = 0; i < count; i++) {
// 取出i位置的成员变量
Ivar ivar = ivars[i];
NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];
[name deleteCharactersInRange:NSMakeRange(0, 1)];
// 设值
id value = json[name];
if ([name isEqualToString:@"ID"]) {
value = json[@"id"];
}
[obj setValue:value forKey:name];
}
free(ivars);
return obj;
}
2.简单的获取成员变量
unsigned int count;
Ivar *ivars = class_copyIvarList([UITextField class], &count);
for (int i = 0; i < count; i++) {
// 取出i位置的成员变量
Ivar ivar = ivars[i];
NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
}
free(ivars);
3.简单的替换方法
// 这个是 Person里面的方法
- (void)run
{
NSLog(@"%s", __func__);
}
// 这个是 myrun 方法
void myrun()
{
NSLog(@"---myrun");
}
// 这个提替换Person类对象中的run方法的imp 为block
class_replaceMethod([Person class], @selector(run), imp_implementationWithBlock(^{
NSLog(@"123123");
}), "v");
// 这个是直接替换函数的实现
class_replaceMethod([MJPerson class], @selector(run), (IMP)myrun, "v");
[person run];