AFAIK当编译器发现任何消息时,它将其转换为带有两个隐藏参数的objc_msgSend – 接收器,选择器和选择器的变量参数.
例如[自测]将是这样的:
objc_msgSend(self,@selector(test));
如果接收者的调度表中没有方法实现,那么函数将尝试在超类中查找实现.
super只是编译器开始在当前对象的超类中搜索方法实现的标志,并且在文档中,apple说当编译器找到’super’时,它会将其转换为类似的东西:
struct objc_super mySuperClass = { self,[self superclass] }; objc_msgSendSuper(&mySuperClass,@selector(forwardedMethod));
我创建了一个包含3个类的项目,每个类都继承自另一个类.
@interface FirstClass : NSObject - (void)forwardMethod; @end @interface SecondClass : FirstClass @end @interface ThirdClass : SecondClass @end
我在根视图控制器中创建了第三个类的实例,并调用了他的方法“forwardMethod”.
实施:
//First Class - (void)forwardMethod { NSLog(@"Base class reached"); } //SecondClass imp - (void)forwardMethod { NSLog(@"second class"); [super forwardMethod]; } //ThirdClass imp - (void)forwardMethod { NSLog(@"third class"); [super forwardMethod]; }
一切正常.但后来我决定解释编译器:
//First Class - (void)forwardMethod { NSLog(@"Base class reached"); } //SecondClass imp - (void)forwardMethod { NSLog(@"second class"); struct objc_super mySuperClass = { self,[self superclass] }; objc_msgSendSuper(&mySuperClass,@selector(forwardMethod)); } //ThirdClass imp - (void)forwardMethod { NSLog(@"third class"); struct objc_super mySuperClass = { self,[self superclass] }; objc_msgSendSuper(&mySuperClass,@selector(forwardMethod)); }
这会导致对第二个类’forwardMethod’的递归调用.我使用self和[self superclass]在第二个类的’forwardMethod’中创建了一个结构,但是self是第三类,
我的超类将永远是’二等’.也许我做错了什么,但我怎么能进入基类’前进方法’?
解决方法
你也是最多的,只有一门课……
要了解为何获得递归,请考虑如何使用编译时和运行时可用的信息找到超类.
在运行时,self的值是对当前对象的引用,您可以使用self来查找对象的类 – 在您的示例中,self是ThirdClass类型的对象.
现在self的值不会随着方法的调用而改变,所以在你的例子中,即使在FirstClass的forwardMethod中,self的值也是对ThirdClass类型的对象的引用.所以self让你能够找到对象的类型,但它并没有告诉你当前在它的继承链中执行方法的位置,所以它本身并不能告诉你该链中的下一个类是什么.
所以考虑编译时间.编译SecondClass时,编译器知道它的超类是FirstClass,因此对super的调用是对FirstClass中方法的调用(除了下面的警告).因此编译器可以使用self和[FirstClass类]来确定调用方法的运行时对象和开始搜索方法的编译时类(因为任何方法查找都是从类开始的搜索并继续进行沿着继承链直到找到实现).所以在你的示例代码中,你只是一个方法:
@implementation SecondClass - (void)forwardMethod { NSLog(@"second class"); struct objc_super mySuperClass = { self,[FirstClass class] }; objc_msgSendSuper(&mySuperClass,@selector(forwardMethod)); }
如果您使用它,您的代码将起作用.但…
……上面提到的那个警告. Objective-C允许使用类调配在运行时更改继承链,因此编译器通常不能依赖编译时继承链来计算超类.那它可以用什么呢?当编译特定方法的源时,它知道方法所属的类,因此它可以将该方法类编译到代码中以查找超类并使用代码开始在运行时的下一个类中搜索方法继承链.这实际上是编译器将为您的代码执行的操作,以防万一您使用了类调码:
@implementation SecondClass - (void)forwardMethod { NSLog(@"second class"); struct objc_super mySuperClass = { self,[SecondClass class] }; objc_msgSendSuper2(&mySuperClass,@selector(forwardMethod)); }
注意编译器传递编译时当前类([SecondClass类])并调用objc_msgSendSuper2来执行查找 – 这将在SecondCLassm之后找到运行时继承链中的第一个方法,而`objc_msgSendSuper将在SecondClass本身开始搜索.
玩得开心,但不要在一般代码中使用它(除非你有一个非常非常非常好的理由;-))