zoukankan      html  css  js  c++  java
  • iOS runtime详解

    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;
    }
  • 相关阅读:
    c函数调用过程
    查找匹配行及前后5行
    指向类成员函数的指针
    C++箴言:理解typename的两个含义
    不定参数
    定时器
    unix编译
    sed
    大脑皮层的梦工厂
    静态链接库顺序问题
  • 原文地址:https://www.cnblogs.com/s-y-j/p/5994438.html
Copyright © 2011-2022 走看看