函数的调用方式
Objective-C是C语言的超集,C语言的函数调用方式是“静态绑定的”,也就是说在编译的时候就知道运行时要调用什么函数,如果调用一个未声明的函数,编译期间就会报错。
void printGoodMorning(){
printf("good morning,huang");
}
void printGoodAfternoon(){
prinf("good afternoon,huang");
}
void helloHuang(int time){
if(time > 6 && time < 12){
printGoodMorning();
}else if(time < 18){
printGoodAfternoon();
}else{
printHelloAllTheTime();//error here
}
}
但是如果我们把上面这段代码改写一下,如下
void printGoodMorning(){
printf("good morning,huang");
}
void printGoodAfternoon(){
prinf("good afternoon,huang");
}
void helloHuang(int time){
void (*hello)();
if(time > 6 && time < 12){
hello = printGoodMorning;
}else if(time < 18){
hello = printGoodAfternoon;
}
hello()
}
你会发现只有当程序运行起来之后,才能知道要执行哪个函数,这就得使用“动态绑定”的概念了
Objective-C是使用传递消息的机制来调用函数,这就会使用到动态绑定的机制在运行期来决定到底调用哪个方法,甚至我们可以在运行时改变对象调用的方法。
对象发送消息大概是这样的:
id returnType = [object messageName:parameter];
编译器会转化为我们断点堆栈中经常能看到的下面这样的C函数:
void objc_msgSend(id self, SEL cmd,...)
这是个参数可以变化的函数,第一个参数代表了消息的接收者,第二个参数是所需要执行的方法名,后面是消息的参数。
objc_msgSend是如何依据消息的接收者和方法名找到合适的方法呢?
首先,需要在接收者所属的类中的方法列表中去查找这个方法,找到了直接调用,没找到则一级一级便利去基类的方法列表,直到NSObject。如果没找到,那么就会触发“消息转发”机制。
消息转发机制如果处理妥当,那么这条消息则能正常处理,如果处理不善,或者根本没处理,那么就会看到我们常看到的崩溃:
-[xxxobject xxxfunc]: unrecognized selector sent to instance 0xxx
简单的解决方案就是,去对应的类添加对应的方法就行了。但是现在我们要提到的是,怎么动态的使用消息转发来处理这个问题。 |