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

3 篇文章 0 订阅

      对于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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值