通俗易懂的ios方法调用底层原理

OC的方法调用的本质是runtime底层调用objc_msgSend,下面我们来分析一下objc_msgSend的具体实现

1、创建一个Person类,有一个对象方法eat和一个实例方法run,并分别调用

@interface Person : NSObject
+(void)eat;//类方法
-(void)run;//实例方法
@end


[Person eat];
    
Person *p = [Person new];
[p run];

每个对象都会有一个它所属的类。这是面向对象的基本概念,但是在OC中,这对所有数据结构有效。任何数据结构,只要在恰当的位置具有一个指针指向一个class,那么,它都可以被认为是一个对象。
在OC中,一个对象所属于哪个类,是由它的isa指针指向的。这个isa指针指向这个对象所属的class。

实际上,OC中对象的定义是如下的样子:

typedef struct objc_object {
      Class isa;
}*id;

这个定义表明:任何以一个指向Class的指针作为首个成员的数据结构都可以被认为是一个objc_object.

最重要的特性就是,你可以向OC中的任何对象发送消息

运行原理就是,当你向一个OC对象发送消息时,运行时库会根据对象的isa指针找到这个对象所属的类.这个类会包含一个所有实例方法的列表及一个指向superclass的指针以便可以找到父类的实例方法。运行时库会在类的方法列表以及父类(们)的方法列表中寻找符合这个selector的方法,找到后即运行这个方法。关键点就是类要定义这个你发送给对象的消息。  

2、类在Runtime中的结构

struct objc_class 
{
    Class isa  OBJC_ISA_AVAILABILITY;
    //isa指针
    //实例的isa指向类对象,类对象的isa指向元类
#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
     //父类

    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;
    //成员变量列表

    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    //方法列表

    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    //方法缓存列表
    //调用过的方法存入缓存列表,下次调用先找缓存

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

#endif

} OBJC2_UNAVAILABLE;

 从上图可以知道Person类本身其实也是一个对象(p对象的isa指针指向Person类,Person类的isa指针指向它的元类meta class)

 

2、方法的调用分为类方法实例方法

2.1实例方法的调用过程( 当你向一个对象发送消息时)

   1.)在对象所属类的<缓存方法列表> 中去找要调用的方法,找到直接执行其实现。
   2.)对象所属类的的<缓存方法列表> 里没找到,就去<类的方法列表>里找,找到了就执行其实现。
   3.)还没找到,说明这个类自己没有了,就会通过super_class去向其父类里执行1、2。
   4.)如果找到了根类还没找到,那么就是没有了,会转向一个拦截调用的方法,可以自己在拦截调用方法里面做一些处理。
   5.)如果没有在拦截调用里做处理,那么就会报错崩溃。

2.2类方法的调用过程( 当你向一个类发送消息时)

   1.)在元类meta class的<缓存方法列表> 中去找要调用的方法,找到直接执行其实现。
   2.)在元类meta class<缓存方法列表> 里没找到,就去<元类的方法列表>里找,找到了就执行其实现。
   3.)还没找到,说明这个类自己没有了,就会通过isa去meta类的父类里执行1、2。
   4.)如果找到了根类还没找到,那么就是没有了,会转向一个拦截调用的方法,可以自己在拦截调用方法里面做一些处理。
   5.)如果没有在拦截调用里做处理,那么就会报错崩溃。

3、这里简单讲一下meta class元类

meta-class,就像Class一样,也是一个对象。你依旧可以向它发送消息调用函数,自然的,meta-class也会有一个isa指针指向其所属类。所有的meta-class使用基类的meta-class作为他们的所属类。具体而言,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己所属的类。
根据这个规则,所有的meta-class使用基类的meta-class作为它们的类,而基类的meta-class也是属于它自己,也就是说基类的meta-class的isa指针指向它自己。(译:完美的闭环)

4、动态方法解析

当本类包括父类直到基类cache包括方法列表class_rw_t中都找不到方法时,就会进入动态方法解析阶段;
动态解析对象方法时,会调用+(BOOL)resolveInstanceMethod:(SEL)sel方法。
动态解析类方法时,会调用+(BOOL)resolveClassMethod:(SEL)sel方法。

5、消息快速转发

当本类没有实现方法,并且没有动态解析方法,就会调用forwardingTargetForSelector函数,进行消息转发,我们可以实现forwardingTargetForSelector函数,在其内部将消息转发给可以实现此方法的对象。
如果forwardingTargetForSelector函数返回为nil或者没有实现的话,就会调用methodSignatureForSelector方法,用来返回一个方法签名,这也是我们正确跳转方法的最后机会。
如果methodSignatureForSelector方法返回正确的方法签名就会调用forwardInvocation方法,forwardInvocation方法内提供一个NSInvocation类型的参数,NSInvocation封装了一个方法的调用,包括方法的调用者,方法名,以及方法的参数。在forwardInvocation函数内修改方法调用对象即可。
如果methodSignatureForSelector返回的为nil,就会来到doseNotRecognizeSelector:方法内部,程序crash提示无法识别选择器unrecognized selector sent to instance。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Oracle数据库是一个关系型数据库管理系统(RDBMS),它采用了客户端/服务器架构,其工作原理如下: 1. 数据库的物理存储:Oracle数据库使用数据文件来存储数据,每个数据文件都由多个数据块组成,每个数据块的大小可以配置,通常为8KB或16KB。Oracle数据库还使用日志文件(redo log和undo log)来记录数据修改和回滚操作。 2. 数据库的逻辑结构:Oracle数据库由表、索引、视图、存储过程等多个逻辑对象组成。表是存储数据的最基本的对象,索引用于加速数据的检索,视图是对表的逻辑上的封装,存储过程是一段可重复使用的程序代码。 3. 数据库的事务机制:Oracle数据库使用ACID模型来保证事务的原子性、一致性、隔离性和持久性。当一个事务被提交时,Oracle会将其所有的修改操作记录到日志文件中,以便在需要时进行回滚或数据恢复。 4. 数据库的并发控制:Oracle数据库使用多版本并发控制(MVCC)来实现并发控制。在MVCC模型中,每个事务看到的数据都是数据库中某个时间点的“快照”,不同的事务之间可以并行执行而不会相互干扰。 5. 数据库的查询优化:Oracle数据库使用CBO(Cost-Based Optimizer)和RBO(Rule-Based Optimizer)两种查询优化器来优化查询语句,使其能够在最短的时间内返回最优的结果。CBO会根据统计信息和成本模型来选择最佳的执行计划,而RBO则根据预定义的规则来选择执行计划。 总之,Oracle数据库工作原理非常复杂,但是在实际使用中,我们只需要了解一些基本的概念和原理即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值