Objective-C PerformSelector 与 objc_msgSend

此文实际成于 2015/08/12

  1. performSelector 是为了方便使用 objc_msgSend 的一个简单的封装
  2. performSelector 只处理了 0-2 个参数的情况,objc_msgSend 可以处理任意多个数参数的情况。

+ (id)performSelector:(SEL)sel {
    if (!sel) [self doesNotRecognizeSelector:sel];
    return ((id(*)(id, SEL))objc_msgSend)((id)self, sel);
}

+ (id)performSelector:(SEL)sel withObject:(id)obj {
    if (!sel) [self doesNotRecognizeSelector:sel];
    return ((id(*)(id, SEL, id))objc_msgSend)((id)self, sel, obj);
}

+ (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
    if (!sel) [self doesNotRecognizeSelector:sel];
    return ((id(*)(id, SEL, id, id))objc_msgSend)((id)self, sel, obj1, obj2);
}

- (id)performSelector:(SEL)sel {
    if (!sel) [self doesNotRecognizeSelector:sel];
    return ((id(*)(id, SEL))objc_msgSend)(self, sel);
}

- (id)performSelector:(SEL)sel withObject:(id)obj {
    if (!sel) [self doesNotRecognizeSelector:sel];
    return ((id(*)(id, SEL, id))objc_msgSend)(self, sel, obj);
}

- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
    if (!sel) [self doesNotRecognizeSelector:sel];
    return ((id(*)(id, SEL, id, id))objc_msgSend)(self, sel, obj1, obj2);
}

objc_msgSend 的 X86_64 汇编实现

objc_msgSend 一系列方法是用汇编实现的。
其中 x86_64 实现如下


/********************************************************************
 *
 * id objc_msgSend(id self, SEL _cmd,...);
 *
 ********************************************************************/
    
    .data
    .align 3
    .globl _objc_debug_taggedpointer_classes
_objc_debug_taggedpointer_classes:
    .fill 16, 8, 0

    ENTRY   _objc_msgSend
    MESSENGER_START

    NilTest NORMAL

    GetIsaFast NORMAL       // r11 = self->isa
    CacheLookup NORMAL      // calls IMP on success

    NilTestSupport  NORMAL

    GetIsaSupport   NORMAL

// cache miss: go search the method lists
LCacheMiss:
    // isa still in r11
    MethodTableLookup %a1, %a2  // r11 = IMP
    cmp %r11, %r11      // set eq (nonstret) for forwarding
    jmp *%r11           // goto *imp

    END_ENTRY   _objc_msgSend

    
    ENTRY _objc_msgSend_fixup
    int3
    END_ENTRY _objc_msgSend_fixup

    
    STATIC_ENTRY _objc_msgSend_fixedup
    // Load _cmd from the message_ref
    movq    8(%a2), %a2
    jmp _objc_msgSend
    END_ENTRY _objc_msgSend_fixedup

你可能感兴趣的:(Objective-C PerformSelector 与 objc_msgSend)