iOS Runtime01 - objc_msgSend消息发送

521 阅读2分钟

一、定义:

Runtime:运行时 就是代码编译时.被装载到内存中去了

二、Runtime的三种调用方式如图:

1.Objctive-C Code方式调用。

2.RunTime API

3.framework&Service

三、探索objc_msgSend流程

通过clang生成ViewController.cpp文件,生成方式如下:
1.终端->cd到你所需要的文件目录下。
方法1:
xcrun -sdk iphonesimulator clang -rewrite-objc ViewController.m
方法2:
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ViewController.m

回归正题探索msgSend准备工作:创建一个类

@interface LGPerson : LGTeacher
- (void)sayHello;
- (void)sayNB:(NSString *)name;
//测试方法
- (void)testFuncation;
@end

@implementation LGPerson
- (void)sayNB:(NSString *)name{
    NSLog(@"%s:666----%@",__func__,name);
}

- (void)sayHello{
    NSLog(@"%s:hello",__func__);
}
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        // sel_registerName = @seletor() = NSSeletorFromString()
        
        // 方法: 消息 : (消息的接受者 . 消息主体)
        LGPerson *person = [LGPerson alloc];
        LGTeacher *teacher = [LGTeacher alloc];
        objc_msgSend(person, sel_registerName("sayNB:"),@"测试");
        objc_msgSend(person, sel_registerName("sayHello"));
        //本类没有相应的方法,会去查询父类。找到了会进行消息发送
        struct objc_super lgsuper;
        lgsuper.receiver = person;
        lgsuper.super_class = [LGTeacher class];
        objc_msgSendSuper(&lgsuper, sel_registerName("sayHello"));
       }
    return 0;
}

结果如下:

objc_msgSend的解析

在.cpp文件发现objc_msgSend,那么objc_msgSend的底层实现应该在汇编里。 底层实现使用汇编的好处:1.效率高,速度快。2.类型的不确定性。所以一般是不带参数进行消息发送

四、objc_msgSend初探

这里我们用的是arm64,消息接受者 :  对象 - ISA - 方法(类) - cache_t - methodlist,在源码中搜素`objc_msgSend`,->objc-msg-arm64.s文件。
找到入口函数:`ENTRY _objc_msgSend`->出口函数:`END_ENTRY _objc_msgSend`
#endif

ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame
//cmp寄存器 p0:判断消息接收是否存在。
cmp	p0, #0			// nil check and tagged pointer check
#if SUPPORT_TAGGED_POINTERS //:若支持SUPPORT_TAGGED_POINTERS类型,则执行下面方法
b.le	LNilOrTagged		//  (MSB tagged pointer looks negative)
#else
b.eq	LReturnZero
#endif
ldr	p13, [x0]    	// p13 = isa
GetClassFromIsa_p16 p13		// p16 = 获取类class,调用GetClassFromIsa_p16,
LGetIsaDone:
// calls imp or objc_msgSend_uncached
//在缓存中获取imp的值
CacheLookup NORMAL, _objc_msgSend

#if SUPPORT_TAGGED_POINTERS
LNilOrTagged:
b.eq	LReturnZero		// nil check

// tagged
adrp	x10, _objc_debug_taggedpointer_classes@PAGE
add	x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
ubfx	x11, x0, #60, #4
ldr	x16, [x10, x11, LSL #3]
adrp	x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE
add	x10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF
cmp	x10, x16
b.ne	LGetIsaDone

// ext tagged
adrp	x10, _objc_debug_taggedpointer_ext_classes@PAGE
add	x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
ubfx	x11, x0, #52, #8
ldr	x16, [x10, x11, LSL #3]
b	LGetIsaDone
// SUPPORT_TAGGED_POINTERS
#endif

LReturnZero:
// x0 is already zero
mov	x1, #0
movi	d0, #0
movi	d1, #0
movi	d2, #0
movi	d3, #0
ret

END_ENTRY _objc_msgSend

总流程如下: