目录

  • 概述
  • 对象与类的实质
    • id与class
    • 继承关系与isa
    • 总结    
  • C函数创建一个OC类
  • OC类与runtime
    • NSObjectProtocol
    • NSObject
    • NSProxy

  Objective-C是开发 osx/ios 的主要语言,它是C语言的一个超集。Objective-C继承了C的基本语法特性,并添加了面对象的特性,所以在Objective-C代码里可以直接写C代码的。在Objective-C里面的对象是一个动态类型,只有在运行时才会被确定下来。在运行时你可以为一个类添加新的方法、属性,也可以修改这个类原有的方法、属性。提供动态添加、修改类的api我们管它叫做runtime api。这一篇文章我们就来学runtime api 、runtime与Objective-C的关系。Objective-C的runtime源码可以从这里获得 runtime 。每个版本的runtime实现不一样,本文以objc4-706.tar.gz为标板。

二、对象与类的实质

 id与class

  在Objective-C里面 id 代表着任意对象,Class代表着任意的类,我们可以看源码的定义:

typedef struct objc_class *Class;
typedef struct objc_object *id;

   可以看出id的实质是机构体objc_object的指针,Class的实质是结构体objc_class的指针。我们在查看结构体objc_object、objc_class的源码(隐藏了一些代码)

  objc_object:

struct objc_object {
private:
    isa_t isa;   // 唯一的成员变量 代表当前对象所指向的类的信息
public:
  // 返回isa的Calss指针  
  Class getIsa();
// 下面还有一系列相关的函数 ...... }

  isa_t:

union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
    struct {
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19;
    };
}

   objc_class:

struct objc_class : objc_object {
    Class superclass;
    const char *name;
    uint32_t version;
    uint32_t info;
    uint32_t instance_size;
    struct old_ivar_list *ivars;
    struct old_method_list **methodLists;
    Cache cache;
    struct old_protocol_list *protocols;
    // CLS_EXT only
    const uint8_t *ivar_layout;
    struct old_class_ext *ext;
    
    // 下面还有一系列相关函数
    ......
}

  从上面我们可以看出2点

  1.objc_object有一个成员变量isa用来保存这个对象指向的类的信息

  2.objc_class继承objc_object,意思就是说class也是对象,我们管它叫做类对象

  既然类对象也是对象,那么类对象自然也有isa成员变量了,oc里面把类对象的isa成员变量指向的类叫做元类(meta class)

  元类是用来实现类方法的,那么元类对象的isa有指向什么呢?oc里面把元类对象的isa指向基类的元类。元类也是有父类...感觉无穷无尽了

  我们还是来看图1吧:

  objective-c runtime 开发详情 

  我们来说明上图

  1.Cat类继承Animal类,Animal类继承NSObject类,cat是Cat的一个实例

  2.cat的对象的isa指向 Cat 类

  3.Cat类的isa指向Cat类的元类(Cat meta class,相应的Animal类的isa指向Animal类的元类(Animal meta class),NSObject类的isa指向NSObject类的元类(NSObject meta class)

  4.Cat类的元类继承Animal类的元类,Animal类的元类继承NSObject类的元类,NSObject类的元类继承NSObject类。

  5.Cat meta class、Animal meta class、NSObject meta class这三个元类的isa都指向根元类(root metaclass)。大部分时候根元类就是NSObject meta class。

 继承关系与isa

  这些继承关系,还有isa构成了oc的对象与类整系统,它们到底怎么发生作用呢,请看下面例子。

@interface Animal : NSObject
+(BOOL)isAnimal; // 是否动物 永远返回ture
-(void)move;     // 移动
@end

@interface Cat :Animal
-(void)eatFish;
@end

  上面是Cat与Animal类的实现,下面代码将展示对象、类怎么调用一个方法的。

Cat *cat = [Cat new];
    
[cat eatFish];
    
[cat move];
    
id newCat = [cat copy];
    
BOOL isAnimal = [Cat isAnimal];

  首先是创建一个Cat的实例

Cat *cat = [Cat new];

  分析上面这句代码前我们先确认一件事:实例方法是在类里实现的,类方法是在类的元类里实现的

  确认了这些事,我们就可以开始分析了

  1.因为new是类方法,所以第一步当然是查询Cat类的isa指向的Cat类的元类(Cat meta class)有没有这个方法,发现Cat meta class 并没有实现new方法。

  2.接着查询Cat meta class的父类即Animal类的元类(Animal meta class)有没有这个方法,发现还是new方法。

  3.再接着查询Animal meta class的父类既NSObject类的元类(NSObject meta class),发现NSObject meta class是有实现new方法的,所以就调用new方法返回一个实例cat。

[cat eatFish];

  这句代码就比较简单了

  先查询cat对象的isa指向的Cat类,有没有实现eatFish这个方法,发现Cat类已经实现了,直接调用既可。

[cat move];

  这个跟[cat eatFish]类似,

  1.先查询cat对象的isa指向的Cat类,发现并没有实现move方法

  2.在查询Cat类的父类Animal类,发现Animal类已经实现了move,直接调用

id newCat = [cat copy];

  这句代码与[cat move]类似

  1.先查询cat对象的isa指向的Cat类,发现并没有实现copy方法

  2.再查询Cat类的父类Animal类,发现并没有实现copy方法

  3.继续查询Animal类的父类NSObject类,发现NSObject类有实现copy方法,直接调用

BOOL isAnimal = [Cat isAnimal];

  这句代码与[Cat new]类似,大家可以试着分析。

 总结

  在Objectative-c里面一个类的实例是一个对象,一个类也是一个对象叫类对象,对象用结构体struct objc_objectl来描述,对象都有一个isa成员变量用来指向这个对象的类。对象实例的方法都走这个对象的类里实现。

  类对象的isa指向这个类对象的类,类对象的类叫做元类。类的方法都在元类里实现。

  元类它也是一个对象叫做元类对象。元类对象的isa指向根元类(root metaclass),根元类在大部分时候都是NSObject meta class。

  当然,类的成员变量、属性、方法、协议等都由相应的机构体来表示,这里就不一一展开了,下文遇到会展开。

 

三、C函数创建一个OC类

  这节我们用runtime的c函数来创建一个oc类,通过这种方式来加深对oc类的理解。

  首先我写了一个方法用于打印一个id对象的类的相关信息,

 1 void rtl_Class(id object){
 2     
 3     // 获取一个对象的class
 4     Class cls = object_getClass(object);
 5     // 获取class 名字
 6     const char * className = class_getName(cls);
 7     printf("%20s :[%p (%s)]\n"  ,"class Name",cls,className);
 8     
 9     // 展示类的继承关系
10     // 获取父类
11     Class superClass = class_getSuperclass(cls);
12     printf("%20s :[%p (%s)]"    ,"class Inherit",cls,className);
13     while (superClass) {
14         printf(" => [%p (%s)]",superClass,class_getName(superClass));
15         superClass = class_getSuperclass(superClass);
16     }
17     printf("\n");
18     
19     // 展示元类的继承关系
20     // 获取一个类的元类
21     Class metaClass = objc_getMetaClass(class_getName(cls));
22     printf("%20s :[%p (%s)]"    ,"meta class Inherit",metaClass,class_getName(metaClass));
23     metaClass = class_getSuperclass(metaClass);
24     while (metaClass) {
25         printf(" => [%p (%s)]",metaClass, class_getName(metaClass));
26         metaClass = class_getSuperclass(metaClass);
27     }
28     printf("\n");
29     
30     // 展示元类的isa信息
31     // isa成员变量在arm64下并不是一个Class的指针,所以不能直接这样使用 Class metaClass = cls->isa;但是可以打印cls->isa的指针
32     metaClass = objc_getMetaClass(class_getName(cls));
33     while (metaClass) {
34         printf("%10s meta class isa :%p \n",class_getName(metaClass),metaClass->isa);
35         metaClass = class_getSuperclass(metaClass);
36     }
37     // 展示类变量列表
38     printf("\nvar List:\n");
39     unsigned int count = 0;
40     Ivar * varList = class_copyIvarList(cls, &count);
41     for (int i=0; i<count; i++) {
42         Ivar var = varList[i];
43         printf("[%30s] [offset:%ld]\n",ivar_getName(var),ivar_getOffset(var));
44     }
45     // 展示属性列表
46     printf("\nproperty List:\n");
47     count = 0;
48     objc_property_t * propList = class_copyPropertyList(cls, &count);
49     for (int i=0; i<count; i++) {
50         objc_property_t property = propList[i];
51         printf("[%30s] [%s]\n",property_getName(property),property_getAttributes(property));
52     }
53     
54     // 展示类方法
55     printf("\nclass method List:\n");
56     Class metaCls = objc_getMetaClass(class_getName(cls));
57     count = 0;
58     Method * methodList = class_copyMethodList(metaCls, &count);
59     for (int i = 0; i < count; i++) {
60         Method method = methodList[i];
61         printf("[%30s]\n",sel_getName(method_getName(method)));
62     }
63 
64     // 展示实例类方法
65     printf("\nclass instance method List:\n");
66     count = 0;
67     methodList = class_copyMethodList(cls, &count);
68     for (int i = 0; i < count; i++) {
69         Method method = methodList[i];
70         printf("[%30s]\n",sel_getName(method_getName(method)));
71     }
72     printf("\n\n");
73 }
View Code

相关文章: