@interfaceViewController :UIViewController
@end
@implementationViewController
- (void)viewDidLoad{
[super viewDidLoad];
[self superHasNotThisSelector];
}
- (void)superHasNotThisSelector{
if([super respondsToSelector:@selector(superHasNotThisSelector)]) {
NSLog(@"superNoHasThisSelector");
}
}
@end
最近突然发现这个问题,当super通过respondsToSelector:这种方式询问是否存在方法时,这个if语句竟然总是为真,本人也是诚惶诚恐,天崩地裂,Why
super是个啥?super并不是隐藏的参数,它只是一个“编译器指示符”。
super调用方法时会执行下面这个代码
id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
第一个参数是个objc_super的结构体,第二个参数SEL,先看下objc_super这个结构体是什么东西:
struct objc_super {
///
Specifies an instance of a class.
__unsafe_unretainedidreceiver;
///
Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus)&&!__OBJC2__
/*
For compatibility with old objc-runtime.h header */
__unsafe_unretainedClass class;
#else
__unsafe_unretainedClass super_class;
#endif
/*
super_class is the first class to search */
};
当然,现在一般我们都使用Objc2版本的runtime库,精简一下就变成如下
struct objc_super {
__unsafe_unretained id receiver;
__unsafe_unretainedClass super_class;
};
msgSendSuper在调用的时候,第一个参数的类型是objc_super这个结构体,
其中,这个结构体里的receiver会存放当前函数里的self(隐式参数)
super_class,会存放[self superclass];
,msgSendSuper寻找方法是从当前对象的父类开始的,并且会沿着父类继承链寻找。在看看令我困惑的语句,
[super respondsToSelector:@selector(superHasNotThisSelector)]
respondsToSelector:这个方法是NSObject的方法,而NSObject类位于所有类的继承链的顶端,因此,执行这个方法时在NSObject的类里找到了对应的实现函数。OC的函数在执行的时候会默认入栈两个参数,第一个参数的类型id,第二个参数的类型是SEL,因此在执行NSObject的respondsToSelector:的实现函数时,把objc_super->receiver和SEL当成隐式参数传给NSObject respondsToSelector:方法
看看NSObject respondsToSelector:的定义
+ (BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector_inst(object_getClass(self), sel, self);
}
因为self 实现了这个方法,因此返回真。
下面我猜测一下objc_msgSendSuper这个方法的实现形式,伪代码应该类似这样
objc_msgSendSuper(struct objc_super *super, SEL op, ...) {
IMP imp =class_getMethodImplementation(super->super_class, op);
imp(objc_super-> receiver, op, …)
}
下面举个小例子,通过绕过super关键字,调用父类方法
@interface Father : NSObject
- (NSInteger)caculateSum:(NSInteger)first second:(NSInteger)second third:(NSInteger)third;
@end
@implementation Father
- (NSInteger)caculateSum:(NSInteger)first second:(NSInteger)second third:(NSInteger)third {
return first + second + third;
}
@end
@interface Son : Father
@end
@implementation Son
- (NSInteger)caculateSum:(NSInteger)first second:(NSInteger)second third:(NSInteger)third {
//我们不采用调super 的方法 [super caculateSum:first second:second third:third];
//模拟super调用
NSInteger(*imp)(id, SEL, NSInteger, NSInteger, NSInteger) = (NSInteger(*)(id, SEL, NSInteger, NSInteger, NSInteger)) class_getMethodImplementation(self.superclass, _cmd);
NSInteger sum = imp(self, _cmd, first, second, third);
return sum;
}
@end
如果调用
Son *son = [[Son alloc]init];
NSInteger sum = [son caculateSum:10 second:20 third:30];
sum将会输出60
夜已经深了,准备睡觉,第一次写技术文档,做为献给我闺女一周岁的礼物~~