上一篇我们讲到iOS对象的底层的本质是结构体!!!这一篇我们来看看我们通过
clang -rewrite-objc main.m -o mian.cpp
编译的对象调用方法底层
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
LGPerson *p = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("new"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
}
return 0;
}
可以看出在我们进行LGPerson
初始化的时候,我们都知道会调用alloc
,init
.我这里为了简单只调用'new'.但是底层不是像我们利用[]
调用的,而是调用了一个函数objc_msgSend
这就是我们消息发送的方法,因为考虑的参数我们进行了前面的强转.如果有一定C功底就知道objc_msgSend
就是发送消息,我们在断点调试ViewDidLoad
的时候,发现能打印self
,_cmd
这就是我们的消息底层默认的两个参数id,SEL
- 一个是消息接受者
- 一个是消息编号
我们还可以在objc_msgSend
末尾继续加参数,但是考虑到编译参数问题,我们需要关闭严格核查
通过SEL
能找到函数实现,底层是依赖一个IMP的函数指针
就会找我们具体的函数实现
我们模拟是不是也可不断发送消息,模拟四种消息发送
LGStudent *s = [LGStudent new];
[s run];
// 方法调用底层编译
// 方法的本质: 消息 : 消息接受者 消息编号 ....参数 (消息体)
objc_msgSend(s, sel_registerName("run"));
// 类方法编译底层
[LGStudent walk];
objc_msgSend(objc_getClass("LGStudent"), sel_registerName("walk"));
// 向父类发消息(对象方法)
struct objc_super mySuper;
mySuper.receiver = s;
mySuper.super_class = class_getSuperclass([s class]);
objc_msgSendSuper(&mySuper, @selector(run));
//向父类发消息(类方法)
struct objc_super myClassSuper;
myClassSuper.receiver = [s class];
myClassSuper.super_class = class_getSuperclass(object_getClass([s class]));
objc_msgSendSuper(&myClassSuper, sel_registerName("walk"));