OC方法列表和方法调用的总结

这两天看了关于iOS运行时的资料,自己做个记录和总结。

 

1.类和对象

OC中的对象相本质上是一个结构体,结构体中包含了一个指向类的指针

 


typedef struct objc_class *Class;

 

/// Represents an instance of a class.

 

struct objc_object {

    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

};

 

类的定义如下:

 

struct objc_class {

    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

 

#if !__OBJC2__

    Class _Nullable super_class                              OBJC2_UNAVAILABLE;

    const char * _Nonnull name                               OBJC2_UNAVAILABLE;

    long version                                             OBJC2_UNAVAILABLE;

    long info                                                OBJC2_UNAVAILABLE;

    long instance_size                                       OBJC2_UNAVAILABLE;

    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;

    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;

    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;

    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;

#endif

 

} OBJC2_UNAVAILABLE;

/* Use `Class` instead of `struct objc_class *` */

没有属性列表,因为属性本质上就是set/get方法 加上成员变量 从上面可以看出实例对象其实是没有方法列表的

2.方法和方法的调用

1).h中只是方法的声明,如果只是在.h中声明了一个方法而没有在.m中实现,则当前对象的方法列表(这里习惯上称为对象的方法列表,从1中可以看出其实是当前对象所属类的方法列表)中是没有该方法的。如果没有在.h中声明某个方法,而在的方法列表.m中实现了某个方法则方法列表中有该方法。

2)实例对象进行方法调用时实际上是消息的发送。通过方法选择器@selector将方法名转化为唯一的一个编号--SEL(这个编号与类和对象无关 只要方法名相同 这个编号就会相同;所以,相同的类不能有相同的方法名),我们可以通过这个编号找到对应的方法实现--IMP(IMP本质上是一个指针,这个指针指向方法实现的首地址)。在查找方法的实现时,首先会去对象所属类的方法列表中查找(如果是类方法,则去元类的方法列表中查找),如果没有找到则会通过super指针去所属类的父类的方法列表中查找,直到顶级父类。

 

/// An opaque type that represents a method selector.

typedef struct objc_selector *SEL;

方法结构体中包含方法名(SEL)和IMP指针

 

struct objc_method {

    SEL _Nonnull method_name                                 OBJC2_UNAVAILABLE;

    char * _Nullable method_types                            OBJC2_UNAVAILABLE;

    IMP _Nonnull method_imp                                  OBJC2_UNAVAILABLE;

 

个人猜测SEL的地址与IMP指针的地址相同 求大神给出答案

 

po [NSString stringWithFormat:@"%p",@selector(func)]

0x109b6a88a

 

po (IMP *)(self,@selector(func));

0x0000000109b6a88a

 

3)如果查到顶级父类后依然没有找到对应的方法,则会进行以下步骤:

 

        ①动态方法解析:系统首先会调用+ (BOOL)resolveInstanceMethod:(SEL)sel方法 我们可以在该方法中通过class_addMethod函数动态添加方法(动态添加的方法要实现)

            ②转发给其他接收者:如果没有通过①来处理消息系统还会给我们机会让我们选择其他接收者来处理这条消息通过

- (id)forwardingTargetForSelector:(SEL)aSelector 方法添加新的接收者

        ③消息完整转发:如果②也都没能处理该消息,系统会给当前接收者最后一次机会(如果在这步仍然没有处理消息则引发异常)把消息转发给其他对象。完整转发就包括了SEL,目标和参数我们可以通过- (void)forwardInvocation:(NSInvocation *)anInvocation 方法来选择要处理当前消息的对象。但是我们需要重写 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 方法 

4)结合1)、2)中的下划线部分可以得出如下结论:子类对象可以调用父类.m中的方法(如果直接调用编译时会出现语法错误,所以可以用[a performSelector:@selector(functionB)]; 来调用。 其中a为A的实例,A继承于B,functionB为B的实例方法,所以我们可以通过这种方式来调用一些类的私有方法)

如果大家碰到什么疑问或者发现错误请告知,大家共同探讨共同进步

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值