我们先创建两个类Person和Student,Student继承自Person类,接下来我们在Student打印如下代码:
@implementation Student
- (void)run{
[super run];
NSLog(@"Student");
}
- (instancetype)init{
if (self = [super init]) {
NSLog(@"[self class] = %@",[self class]);//Student
NSLog(@"[self superclass] = %@",[self superclass]);//Person
NSLog(@"----------------------");
NSLog(@"[super class] = %@",[super class]);//Student
NSLog(@"[super superclass] = %@",[super superclass]);//Person
}
return self;
}
@end
发现super跟self好像效果都是一样的。这是什么原因,那我们就需要去看看super方法的底层调用了。我们看下run方法底层是怎样的?
- (void)run{
[super run];
NSLog(@"Student");
}
struct __rw_objc_super arg = {
(id)self,//消息接收者
(id)class_getSuperclass(objc_getClass("Student"))//消息接收者的父类
};
objc_msgSendSuper(arg,
@selector(run));
可以看到super是通过objc_msgSendSuper发送消息,其中arg中消息接收者还是self。传进去的那个父类是表示直接从父类去查找方法,而不是跟往常一样从当前对象查找。那么[super class]就是直接从父类Person去搜索,而class方法在NSObject里面,class的底层实现是这样
- (Class)class{
return object_getClass(self);
}
class调用返回值取决于方法接收者self跟父类无关,所以打印的还是Student。
superClass的底层实现是这样:
+ (id)superclass
{
return self->superclass;
}
- (id)superclass
{
return isa->superclass;
}
其实返回的就是消息接收者的父类
总结:super的本质是:(1)消息接收者还是当前对象,并不是父类。(2)super方法调用时是直接从父类去查找方法,而不是从当前对象开始查找
isMemberOfClass和isKindOfClass区别
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
很明显isMemberOfClass是判断当前对象是否是这个类对象。
isKindOfClass稍微复杂一点,首先是拿当前对象的类对象去比较看是否相等,如果不相等就跟父类比,直到NSObject基类。