深入理解Objective-C方法调用

  我们知道,在 Objective-C 中,所有的 [receiver message]都会转换为 objc_msgSend(receiver, @selector(message))调用,
objc_msgSend的调用又涉及到方法查找、消息动态处理,消息转发等过程。下面我们结合 objc 的源码来深入了解 Objective-C 的方法调用流程。
  在开始前我们需要了解几个概念:SEL,IMP,Method:

1. 概念:

1.1 SEL

objc.h中,SEL如下定义

/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;

1.2 IMP

objc.h中,IMP如下定义

/// A pointer to the function of a method implementation. 
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ ); 
#else
typedef id (*IMP)(id, SEL, ...); 
#endif

1.3 Method

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

Method = SEL + IMP + method_types,相当于在SEL和IMP之间建立了一个映射。

2. Objective-C 方法调用流程

参考 objc_msgsend-part-1-the-road-map,通过对objc_msgSend的汇编源码分析,总结出以下流程:

  1. 检查selector是否需要忽略
  2. 检查target是否为nil:
    1. 如果设置了nil处理函数,跳转到对应函数
    2. 如果没有则直接清空返回
  3. 从target的class中根据selector查找IMP并跳转到对应实现

2.1 寻找IMP流程

  1. 在当前class的缓存列表(cache methodLists)中寻找,如果找到则跳到对应实现;否则继续执行
  2. 从当前class的方法列表(methodLists)中查找,找到了添加到缓存列表并跳转到对应实现;否则继续执行
  3. 从父类的缓存列表及方法列表查找,直到找到NSObject为止,找到了添加到缓存列表并跳转到对应实现;否则继续执行
  4. 以上步骤找不到IMP,则进入消息动态处理消息转发流程

2.2 消息动态处理及消息转发流程

  1. + (BOOL)resolveInstanceMethod:(SEL)sel 方法动态决议,利用runtime的特性动态添加方法
void dynamicMethodIMP(id self, SEL _cmd)
{
    // implementation ....
}

+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
    if (aSEL == @selector(resolveThisMethodDynamically))
    {
          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
          return YES;
    }
    return [super resolveInstanceMethod:aSel];
}
  1. - (id)forwardingTargetForSelector:(SEL)aSelector; 将消息转发给代理对象处理
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    //如果代理对象能处理,则转接给代理对象
    if ([proxyObj respondsToSelector:aSelector]) {
        return proxyObj;
    }
    //不能处理进入转发流程
    return nil;
} 
  1. 消息转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation

注意:如果 methodSignatureForSelector返回nil则不会继续执行 forwardInvocation,转发流程终止,抛出无法处理的异常。

如果 methodSignatureForSelector返回方法签名非nil,我们还有最后一次机会处理这个消息,那就是在forwardInvocation 回调里进行消息转发,具体如下:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *sig = [friend methodSignatureForSelector:@selector(bb_dealNotRecognizedMessage:)];
    return sig;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    SEL aSelector = [invocation selector];
     if ([friend respondsToSelector:aSelector])
        [invocation invokeWithTarget:friend];
    else
        [super forwardInvocation:invocation];
}

2.3 . 消息异常处理: - (void)doesNotRecognizeSelector:(SEL)aSelector;

完整流程如下


深入理解Objective-C方法调用_第1张图片

你可能感兴趣的:(深入理解Objective-C方法调用)