iOS runtime详解

mac2022-06-30  11

runtime(运行时机制)

简介

1.Runtime是一套底层的纯C语言的API,属于C语言的一个库,里面包含了很多底层的C语言的API 2.平时编写的OC代码,在程序运行过程中,其实最终都转成了runtime的C语言的代码,runtime算是OC的幕后工作者 3.比如这段OC代码: XPerson *obj = [[XPerson alloc] init]; obj.name = @"syj"; runtime C 代码: XPerson *obj = objc_msgSend(objc_msgSend(objc_getClass("XPerson),@selector(alloc)),@selector(init)); objc_msgSend(obj,@selector(setName:),@"syj");

runtime的作用

1.在程序运行中动态创建一个类(比如KVC、KVO的底层实现) 2.在程序运行中动态为某个类添加属性和方法,修改属性的值和方法 3.遍历一个类的所有属性和方法(字典转模型,归档时用循环实现)

runtime相关应用

1.NSCoding(归档和解档) 2.字典转模型(json解析封装的那个函数) 3.KVO(利用runtime动态生成一个类) 4.可以用于开发框架(方便更改)

runtime相关的头文件

#import <objc/runtime.h> 包含对类、成员变量、属性、方法的操作 #import <objc/message.h> 包含消息机制

runtime常用方法

objc_msgsend:给对象发送消息 class_copyMethodList:遍历某个类所有的方法 class_copyIvarList:遍历某个类所有的成员变量

runtime官方文档(部分摘选)

Method
Method 代表类中某个方法的类型 typedef struct objc_method *Method; struct objc_method { SEL method_name //方法名类型为SEL char *method_types //方法类型是个char指针,存储方法的参数类型和返回值类型 IMP method_imp //method_imp指向了方法的实现,本质是一个函数指针 } objc_method存储了方法名,方法类型,方法实现
Ivar
Ivar 是表示成员变量的类型 typedef struct objc_ivar *Ivar; struct objc_ivar { char *ivar_name char *ivar_type int ivar_offset //基地址偏移字节 #ifdef __LP64__ int space #endif }
Category
typedef struct objc_category *Category; struct objc_category { char *category_name char *class_name struct objc_method_list *instance_methods struct objc_method_list *class_methods struct objc_protocol_list *protocols }
Property
typedef struct objc_property *objc_property_t; 可以通过class_copyPropertyList和protocol_copyPropertyList方法获取类和协议中的属性
Class
Class是指向objc_class结构体的指针 struct objc_class { Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__ Class super_class //父类指针 const char *name //类名 long version long info long instance_size struct objc_ivar_list *ivars //成员变量列表 struct objc_method_list **methodLists //方法列表 struct objc_cache *cache //缓存 struct objc_protocol_list *protocols //协议 #endif } /* Use `Class` instead of `struct objc_class *` */

字典转模型

+ (NSMutableArray *)customModel:(NSString *)modelClass ToArray:(id)jsonArray { //用来存放一个类中有几个成员变量。 unsigned int outCount = 0; //这句话执行之后outCount的值就会是当前类中属性的个数。整体返回的是一个指针数组,里面包含对应类的各个属性信息。 objc_property_t *properties = class_copyPropertyList(objc_getClass(modelClass), &outCount); //创建一个数组用来存放对象; NSMutableArray *objectArr = [[NSMutableArray alloc] initWithCapacity:1]; for (int i = 0; i < [jsonArray count]; i++) { //取出数组中的一个对象 id jsonDic = [jsonArray objectAtIndex:i]; //若数组中的对象不是字典对象就跳过它。继续下一个。 if(![jsonDic isKindOfClass:[NSDictionary class]]) { continue; } //创建一个传过来字符串(类名)相应的对象 id model = [[objc_getClass(modelClass) alloc] init]; // [model setValuesForKeysWithDictionary:jsonDic]; //判断类中的每一个属性 for (int j = 0; j < outCount; j++) { //获取类中的第j个成员变量信息 objc_property_t property = properties[j]; //获取类中的第j个成员变量将其转化为字符串 NSString *propertyName =[NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding]; //获得json串中的键对应的值 id value = [jsonDic objectForKey:propertyName]; //判断上面取得的值是否存在,不存在就去转换下一个属性 if(!value || [value isKindOfClass:[NSNull class]]) { continue; } [model setValue:value forKey:propertyName]; } //把转化完成的对象加到一个数组中。 [objectArr addObject:model]; } CFRelease(properties); return objectArr; }

归档解档

把自己定义的类所创建的对象直接写入文件的步骤:

自定义类遵循NSCoding协议,实现NSCoding协议中的两个方法: encodeWithCoder:往文件中写入实例变量 initWithCoder:从文件中读取实例变量为当前对象赋值 如何把对象写入文件:调用NSKeyedArchiver中的archiverRootObject:toFile: 如何把对象从文件中读取出来:调用NSKeyedUnarchiver中的unarchiveObjectWithFile:

代码如下:

//归档(将数据存入文件) - (void)encodeWithCoder:(NSCoder *)aCoder { //归档存储自定义对象 unsigned int count = 0; //获得指向该类所有成员变量的指针 Ivar *ivars = class_copyIvarList([self class], &count); for (int i = 0; i < count; ++i) { Ivar ivar = ivars[i]; //获得成员变量的名称 const char *keyName = ivar_getName(ivar); NSString *key = [NSString stringWithUTF8String:keyName]; //编码每个属性,利用KVC取出每个属性对应的值 [aCoder encodeObject:[self valueForKey:key] forKey:key]; } free(ivars); } //解档并初始化(读取文件中的数据) - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { unsigned int count = 0; //获取指向该类所有成员变量的指针 Ivar *ivars = class_copyIvarList([self class], &count); for (int i = 0; i < count; ++i) { Ivar ivar = ivars[i]; //获得成员变量的名称 const char *keyName = ivar_getName(ivar); NSString *key = [NSString stringWithUTF8String:keyName]; //解码每个属性,利用KVC为每个属性赋值 [self setValue:[aDecoder decodeObjectForKey:key] forKey:key]; } free(ivars); } return self; }

转载于:https://www.cnblogs.com/s-y-j/p/5994438.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)