iOS开发-------初探运行时runtime

来源:互联网 发布:vr用什么软件 编辑:程序博客网 时间:2024/06/05 19:35

      对于iOS的开发者,相信Objc的runtime机制肯定都听说过,了解runtime的机制,对自己的提高不言而喻,最近在一直学习runtime机制,对此写下点学习过程的收获,以便以后查阅,也方便理解,本人研究runtime时间不长,如果有理解不对的地方也请告知,共同进步。


     什么叫runtime呢,大家也都知道Objc的底层是C语言完成的,在运行的时候,会将Objc的代码转换成C语言的代码,这段过程就是所说的运行时runtime。比如执行一个方法的执行: [target action];这段代码会在runtime的时候转换为objc_msgSend(target,@selector(action));

      

要想了解RunTime,首先了解的必然是类的结构,在Objc中所有的东西都可以看做是一个对象,实例对象是一个对象,类也是一个对象,打开objc/runtime.h,研究一下他的结构:

/// An opaque type that represents a method in a class definition.typedef struct objc_method *Method;//描述类的一个方法/// An opaque type that represents an instance variable.typedef struct objc_ivar *Ivar;//实例变量/// An opaque type that represents a category.typedef struct objc_category *Category;//类目/// An opaque type that represents an Objective-C declared property.typedef struct objc_property *objc_property_t;//类中声明的属性

struct objc_class {    Class isa  OBJC_ISA_AVAILABILITY;//指向类结构的指针#if !__OBJC2__    Class super_class                                        OBJC2_UNAVAILABLE;//父类,如果此类是根类,则为NULL    const char *name                                         OBJC2_UNAVAILABLE;//类名    long version                                             OBJC2_UNAVAILABLE;//版本号    long info                                                OBJC2_UNAVAILABLE;//标志位    long instance_size                                       OBJC2_UNAVAILABLE;//实例对象的大小    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;//实例变量的列表,没有则为NULL    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;//存储对象方法列表,没有则为NULL    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;//缓存最近使用过的方法,提高运行效率    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;//存储遵守正式协议的列表,没有则为NULL#endif} OBJC2_UNAVAILABLE;

      看到这段代码,想起之前看到过罗朝辉出过的一本书,上面在这里面讲的一句话是"内存布局以一个objc_class指针为开始的所有东东都可以当做一个object来对待"。


      isa指针是个什么东东呢,它是一个Class类型的指针,如果这个类是一个实例对象(instance object),那么它的isa指针就指向它所属于的类对象的类(class  实例对象的isa指针指向的类对象为class,class中存储着普通成员变量以及普通的方法,即-方法),如果这个类是一个类对象(class object),那么它的isa指针就指向了metaClass(类对象isa指向的类结构为metaclass,metaclass中存储着类的Static类成员变量以及Static方法,即+方法)


      如果有点乱的话,官方有一张图很清晰的描述了他们之间的关系,如下

                   


      只说无代码是枯燥的,为了测试一下简单的RunTime机制,创建一个RunTimeTextClass类

////  RunTimeTextClass.h//  RunTime////  Created by YueWen on 16/2/21.//  Copyright © 2016年 YueWen. All rights reserved.//#import <Foundation/Foundation.h>@protocol Protocol1;@protocol Protocol2;@interface RunTimeTextClass : NSObject<Protocol1>{    NSString * ival1;    NSString * ival2;}@property (copy, nonatomic)NSString * title;@property (assign, nonatomic)NSInteger index;- (void)objctFunction;+ (void)classFunction;@end@protocol Protocol1 <NSObject>@optional- (void)text1;@end@protocol Protocol2 <NSObject>@optional- (void)text2;@end

////  RunTimeTextClass.m//  RunTime////  Created by YueWen on 16/2/21.//  Copyright © 2016年 YueWen. All rights reserved.//#import "RunTimeTextClass.h"@interface RunTimeTextClass()<Protocol2>{    NSString * ival1M;}@property (nonatomic, copy)NSString * titleM;//.m中的属性@end@implementation RunTimeTextClass-(void)objctFunction{    }@end


获取类的属性列表

//获取类的属性列表unsigned int propertyCount;objc_property_t * propertyList = class_copyPropertyList([RunTimeTextClass class], &propertyCount);//获取属性的数组列表for (int i = 0; i < propertyCount; i ++)//开始遍历{    //获取属性名字    const char * name = property_getName(propertyList[i]);    NSLog(@"property = %@",[NSString stringWithUTF8String:name]);}

打印结果如下:



获取类的实例变量列表

//获取类的实例变量列表unsigned int ivarCount;Ivar * ivars = class_copyIvarList([RunTimeTextClass class], &ivarCount);//获取实例变量的列表for (int i = 0; i < ivarCount; i++)//开始遍历{    //获取实例变量的名字    const char * name = ivar_getName(ivars[i]);    NSLog(@"ivar = %@",[NSString stringWithUTF8String:name]);}

打印结果如下:    从结果来看,每创建一个属性,运行时会响应的创建一个_(propertyName)的实例变量




获取类中已经实现的方法列表

    //获取已经实现的方法列表    unsigned int methodCount;        Method * methods = class_copyMethodList([RunTimeTextClass class], &methodCount);        for (int i = 0; i < methodCount; i++)    {        //获取方法名字        Method method = methods[i];        NSLog(@"method = %@",NSStringFromSelector(method_getName(method)));    }

运行结果如下:看出没有实现的方法并没有进行打印,并且用@property声明的变量在RunTime会自行的创建它的Get和Set方法




获取遵守的协议列表

    //获取协议的列表    unsigned int protocolCount;    __unsafe_unretained Protocol ** protocols = class_copyProtocolList([RunTimeTextClass class], &protocolCount);        for (int i = 0; i < protocolCount; i++)    {        //获取协议        Protocol * protocol = protocols[i];                //获得协议名称        const char * name = protocol_getName(protocol);        NSLog(@"Protocol = %@",[NSString stringWithUTF8String:name]);    }


运行结果如下:(Protocol2是在延展中遵守,Protocol1是在声明文件中遵守)



      RunTime到底有什么用呢,比如字典转模型的时候,我想属性的名字和字典的索引名字相同,但是实际上属性的名称与字典的key值并不匹配,那么就可以在RunTime中对类进行添加属性。RunTime研究起来很有意思,想以后会陆续的写一些关于RunTime的东西。

0 0
原创粉丝点击