OC Runtime中的Object&Message

本文深入探讨了Objective-C运行时的核心概念,包括Object的真实面目、Class结构体的组成及其内部isa和super_class指针的工作原理,并解析了消息传递机制及方法查找流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该文中所有的结构体定义都可以在runtime.h文件中找到

Object

先上一张图,然后围绕这个图开始介绍

Object

OC是基于C语言的一个超类,OC里类的概念和java,c++等语言的类在语法上很相似,但是实际在底层执行的时候并不一样,因为C语言中没有类这个概念,而所有的OC语言,最终在执行的时候都是转换成C语言来执行,那么问题来了,OC中的Object究竟是一个什么概念,它在C语言层面是一个什么样的形式?

图的左边是一个OC的实例,这个实例中有一个isa指针,指针是Class类型,这个指针指向的就是这个实例的定义。Class指针在内部被定义为:

   typedef  struct objc_class *Class

object_class是用C语言定义的一个结构体,这个就是OC中的Object真实的面目。图右显示了该结构体组成,下面开始逐个解释每个属性的作用:

1.Class isa

实例的isa指针是指向这个实例的类结构体,相当于是元类(meta-class)。而每个类结构体中也有isa指针,此时可以在将这个类结构体看成一个实例,它的isa指针也是指向这个类的元类。看下面的代码:

        @interface MyController:ViewController
        -(void)func1;
        -(void)func2;
        +(void)func3;
        +(void)func4;
        ...
        ...
        MyViewController *myVC = [MyViewController alloc] init];

上面代码定义个了一个MyController的类,包含两个实例方法(func1,func2)和两个类方法(func3,func4)。后面定义了一个myVC实例,此时myVC中的isa指针指向的就是MyController的objc_class结构体,但是此时这个结构体中的方法列表是不包含func3和func4这两个类方法的,MyController结构体中的isa指针指向MyController的元类(meta-class)结构体,这个meta-class结构体中的方法列表包含了func3和func4这两个类方法。这里有一个问题,每一个meta-class本身也是可以看做一个实例,可以向它发送消息,那它的isa指针又指向谁呢?为了避免无限延伸,所有的meta-class结构体中的isa指针最终都会指向NSObject,而NSObjec中的isa指针则指向自己,形成一个回路。

2.Class super_class
super_class从字面很容易理解,就是指向父类的结构体,最终super _class指针会指向root class(NSObject或者NSProxy),root class的super _class指针为nil。

借用南峰子的技术博客上的一张图,图示isa和super_class指针:
isa&super_class

上图的class,meta class,super class和super meta class的关系可以在runtimeobjc-runtime-new.mm的代码中找到:
每当创建一个新的class的时候,会调用objc_allocateClassPair方法

// Connect to superclasses and metaclasses
    cls->initClassIsa(meta);
    if (superclass) {
        meta->initClassIsa(superclass->ISA()->ISA());
        cls->superclass = superclass;
        meta->superclass = superclass->ISA();
        addSubclass(superclass, cls);
        addSubclass(superclass->ISA(), meta);
    } else {
        meta->initClassIsa(meta);
        cls->superclass = Nil;
        meta->superclass = cls;
        addSubclass(cls, meta);
    }

3.const char *name
类名sdsds

4.long version
5.long info
6.long instance_size

7.struct objc_ ivar_ list *ivars
类中定义的变量都存在这个列表里。

8.struct objc _method _list **methodLists
类中定义的方法都存放在这个列表里,该列表的会在后面详细介绍。

9.struct objc_cache *cache
这是一个缓存列表,用于缓存那些已经被调用过的方法,当再次访问同一个方法就会到这个列表中去查找,加快了方法的访问速度。

10.struct objc_protocol _list *protocols
保存该类要实现的protocol。



Message

在介绍这一节之前,首先明确一下method和message的区别:

在java或c++中,method是一段代码,这段代码与某一个Class相关联。
在OC中,从语法层面来看,调用类中的方法看起来和java这种语言很类似,实际在调用一个方法时,是向Class发送了一条消息。然后由这个Class去处理消息。

 [obj fun:@"hello"]; // OC语法
 objc_msgSend(obj,@selector(fun:),@"hello"); //实际触发的方法。

从上面代码可以看到,在OC中调用方法的代码,都会被转换成objc_msgSend(id,SEL,…)这种形式,其中第一个参数是Object,就是接收消息的类,第二个参数是方法名,后面的参数是方法中的参数。

了解了在OC中调用方法的基本概念后,来看一下Method的定义:

Message         

前面在讲Object的结构的时候,提到存储方法的列表是一个叫做objc_method _list的结构体,如上图所示,这个结构体有四个属性。

在这个结构体中, 还有一个方法列表objc_method 这个列表才是真正存储方法的列表,从图右可以看到这个结构体的定义。分别记录了方法名,方法的返回类型以及IMP,IMP是方法的具体执行代码的地址,也可以叫做函数指针。

   typedef id (*IMP)(id, SEL, ...); 

现在来理一遍当执行一个方法的流程:当objc_msgSend被执行时,首先通过isa指针找到struct objc _class,然后定位到objc _method _list,通过查找obj _method 列表中method _name,如果找到,则根据IMP来执行,否则在去super _class中查找。

这里有一个问题,如果每次都要从objc_method _list中去线性超找方法名效率会比较低,尤其是含有大量方法的时候。查找会很慢,为了解决这个问题。objc _class结构体中,有一个struct objc _cache *cache的列表,当第一次执行某一个方法时,会在objc _method _list中找,然后这个方法会被记录在cache列表中,下次再执行时则直接从cache中去查找。下面看一下struct objc _cache的定义:

 struct objc_cache {
     unsigned int mask /* total = mask + 1 */;
     unsigned int occupied;
     Method buckets[1];
 }

该结构体定义了一个hash table存储在Method中(Method也是一个objc_method指针),其中selector被当作key。

如果有任何问题欢迎再下面留言,或者扫描二维码
wechat

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值