Object-C Runtime 运行时

2015-12-26  本文已影响306人  Karen_

Runtime 运行时

参考文章:
玉令天下的博客
特酷吧
南峰子的技术博客
顾 鹏


Objective-C是动态语言,所以需要编译器的同时也需要一个运行时系统来动态创建对象、传递消息。在你需要的时候还能对其进行扩展,解决问题。Objective-C的Runtime是一个运行时的库(Runtime Library),主要使用C和汇编写的库,为C添加了面向对象的能力并创造了Objective-C。这个运行时系统就像一个操作系统一样:它让所有的工作正常运行。有动态类型(Dynamic typing),动态绑定(Dynamic binding)和动态加载(Dynamic loading)
Runtime有两个版本:ModernLegacy。Object—C2.0采用的是Modern版本的Runtime,只能在iOS和OS X10.5之后的64位程序上运行。32位程序采用Legacy版本的Runtime。它们的区别在于更改实例变量时,Legary需要重新编译其子类,而Modern`则不需要。

打开终端进入工程目录

找到工程的.main文件层级 输入命令 clang -rewrite-objc main.m
文件夹内就可以找到.cpp文件,打开可以看到很多C的代码所以有人说OC是假的面向对象


Class为指向类的结构体指针typedef struct objc_class *Class;,该类的结构体包含:

struct objc_class {

    Class isa  OBJC_ISA_AVAILABILITY; // isa指针


#if !__OBJC2__

    Class super_class                  OBJC2_UNAVAILABLE;  // 父类

    const char *name                   OBJC2_UNAVAILABLE;  // 类名

    long version                       OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0

    long info                          OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识

    long instance_size                 OBJC2_UNAVAILABLE;  // 该类的实例变量大小

    struct objc_ivar_list *ivars       OBJC2_UNAVAILABLE;  // 该类的成员变量链表

    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表

    struct objc_cache *cache           OBJC2_UNAVAILABLE;  // 方法缓存

    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表

#endif


} OBJC2_UNAVAILABLE;

isa 指针指向objc_class结构体的指针

  NSObject *objc = [[NSObject alloc]init];
  objc->isa; // 警告:会提示你用 **object_getClass(objc);**替换
SunnyXX之前的题

为什么[NSObject foo]可以调用实例方法?

Method 方法的类型

typedef struct objc_method *Method;
objc_method结构体如下

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}  

SEL

等同于Object-C中selectorselector是方法选择器
typedef struct objc_selector *SEL;SEL是指向objc_selector的指针,不同类中相同名字的方法所对应的方法选择器是相同的,即使方法名字相同而变量类型不同也会导致它们具有相同的方法选择器 因为不同类的实例对象用相同的方法选择器时,会在各自的消息选择、实现地址、方法链表中根据 selector 去查找具体的方法实现IMP。这也是动态的过程,也就是说在运行之前甚至编译的时候我们都不知道最终会执行哪行代码。

IMP

IMP在objc中的定义为`typedef id (*IMP)(id, SEL, ...);
前面也提到它是个 函数指针上面SEL里提到只有在编译的时候才会知道最终实现哪行代码,就是因为编译时IMP这个函数指针指向了最终实现的代码。方法名相同的时候通过IMP的参数类型就能将它们区分开找到特定的那个方法的实现。

Cache

struct objc_cache {

    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;

    unsigned int occupied                                    OBJC2_UNAVAILABLE;

    Method buckets[1]                                        OBJC2_UNAVAILABLE;

};

南峰子的技术博客对objc_cache结构体描述的很详细:

Ivar 实例变量的类型

typedef struct objc_ivar *Ivar;

struct objc_ivar {
  char *ivar_name                                          OBJC2_UNAVAILABLE; // 名称
  char *ivar_type                                          OBJC2_UNAVAILABLE; // 类型
  int ivar_offset                                          OBJC2_UNAVAILABLE; // 偏移量
#ifdef __LP64__
  int space                                                OBJC2_UNAVAILABLE;
#endif
}  

id是一个objc_object类型指针


引入头文件
#import <objc/runtime.h>
#import <objc/message.h>

`#import <objc/runtime.h>`
`#import <objc/message.h>`
Class cls = [per class];// 获取自己的类
const char *className =  class_getName(cls); // 获取类名
NSLog(@"%s",className);

 // 2. meta-class 元类
 // 1>当我们调用实例方法时,系统会去类的列表里找对应名字的方法
 // 2>当我们调用类方法时,系统会去meta-class(元类)的列表中找对应名字的方法
        
  // 寻找对象的元类 object_getClass(填入的是类对象)
       Class metaClass =  object_getClass(cls);
       BOOL isMetaClass = class_isMetaClass(metaClass);// 判断是不是元类
       NSLog(@"是否是元类%d",isMetaClass);
        
       // 3. 获取属性列表 如果有属性count就有值
        unsigned int count = 0;
        Ivar *ivarList = class_copyIvarList(cls,&count);
        // 循环遍历类获取其属性
        for (int i = 0; i < count; i++) {
            Ivar ivar = ivarList[i];
            NSLog(@"Person类的成员变量列表下标%d以及属性名%s",i,ivar_getName(ivar)); // _name _sex _age _hobby
        }
        
        // 4.获取属性列表
        unsigned int outCount = 0;
        objc_property_t *properList = class_copyPropertyList(cls, &outCount);
        for (int i = 0; i < outCount; i++) {
            objc_property_t property = properList[i];
            
            unsigned int attributeCount = 0;
         objc_property_attribute_t *attribute =  property_copyAttributeList(property,&attributeCount); // 属性列表内部
            for (int j = 0 ; j < attributeCount; j++) {
                NSLog(@"%s : %s",attribute[j].name,attribute[j].value);
            }
            
            NSLog(@"Person类的属性列表下标%d以及属性名%s",i,property_getName(property));
        }
        
        // 方法列表
        unsigned int methCount= 0;
       Method *methList = class_copyMethodList(cls,&methCount);
        for (int i = 0; i < methCount; i++) {
           Method meth = methList[i];
            NSLog(@"Person方法名%@",NSStringFromSelector(method_getName(meth)));
        }

上一篇 下一篇

猜你喜欢

热点阅读