14-self与super以及isMemberOfClass与isKindOfClass的区别

简介: 14-self与super以及isMemberOfClass与isKindOfClass的区别

self 与 super

思考如下代码的打印结果?

@interface Person : NSObject
@end
@implementation Person
@end
@interface Student : Person
@end
@implementation Student
- (instancetype)init {
    if (self = [super init]) {
        NSLog(@"%@", [self class]); //打印结果:Student
        NSLog(@"%@", [self superclass]); //Person
        NSLog(@"%@", [super class]); //Student
        NSLog(@"%@", [super superclass]); //Person
    }
    return self;
}
@end

打印结果:

Student
Person
Student
Person

1. 利用以下命令看下[super class]的底层调用:

xcrun -sdk iphoneos clang -arch arm64 -F Foundation.framework -rewrite-objc main.m -o main.cpp

2. 可以看到[super class]转换为了如下代码:

((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"));

简化后如下:

(objc_msgSendSuper)({self, class_getSuperclass(objc_getClass("Student"))}, @selector(class));

3. 通过源码看下objc_msgSendSuper的底层实现如下

objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)

可以看到第一个参数为objc_super结构体,第二个参数为SEL类型,其中objc_super的结构如下:

struct objc_super {
    __unsafe_unretained _Nonnull id receiver; // 消息接收者
    __unsafe_unretained _Nonnull Class super_class; // 消息接收者的父类
};

第一个成员为receiver也就是消息接收者,第二个参数为Class;4. 通过[super class]的简化后代码可知:

(objc_msgSendSuper)({self, class_getSuperclass(objc_getClass("Student"))}, @selector(class));

其中class的实现为:

- (Class)class {
    return object_getClass(self);
}

receiver参数值为self,super_class参数值为Student类对象的父类,也就是Person,SEL为class,意思为调用class方法的时候从Person类里面去找,消息接收者依旧为当前类,结合class的内部实现,也就是self的class对象,故此处为Student;

[super superclass]同理,消息接收者receiver参数值为self,super_class参数值为Student类对象的父类,也就是Person,SEL为superclass,故此处为Student的父类,也就是Person;

总结无论是self或者super真正调用的对象都是一样的,也就是消息接收者是一致的,只是方法查找的位置不一样,self是从当前类结构中开始查找,super是从父类中查找,但方法的接收者都是当前类或者当前类的对象;isKindOfClass: 与 isMemberOfClass: 思考如下代码的打印结果?

@interface Person : NSObject
@end
@implementation Person
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [Person new];
        BOOL ret1 = [person isKindOfClass:[NSObject class]]; //打印结果: 1
        BOOL ret2 = [person isKindOfClass:[Person class]]; //打印结果: 1
        BOOL ret3 = [person isMemberOfClass:[NSObject class]]; //打印结果: 0
        BOOL ret4 = [person isMemberOfClass:[Person class]]; //打印结果: 1
        NSLog(@"%d - %d - %d - %d", ret1, ret2, ret3, ret4);
        BOOL ret5 = [[NSObject class] isKindOfClass:[NSObject class]]; //打印结果: 1
        BOOL ret6 = [[NSObject class] isMemberOfClass:[NSObject class]]; //打印结果: 0
        BOOL ret7 = [[Person class] isKindOfClass:[Person class]]; //打印结果: 0
        BOOL ret8 = [[Person class] isMemberOfClass:[Person class]]; //打印结果: 0
        BOOL ret9 = [[Person class] isKindOfClass:[NSObject class]]; //打印结果: 1
        NSLog(@"%d - %d - %d - %d - %d", ret5, ret6, ret7, ret8, ret9);
    }
    return 0;
}

打印结果:

1 - 1 - 0 - 1
1 - 0 - 0 - 0 - 1

isKindOfClass: 与 isMemberOfClass: 底层源码实现

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}
- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}

通过源码可知:

  • isMemberOfClass:
    如果是类对象比较的是类对象的isa(也就是元类对象)与传入类对象进行比较;如果是实例对象比较的是实例对象的类对象与传入的类对象进行比较;


  • isKindOfClass:
    如果是类对象比较的是通过当前类对象isa(也就是元类对象)与传入的类对象进行比较,并依据当前类对象逐层向上查找是否相等;如果是实例对象比较的实例对象的类对象与传入的类对象进行比较,并依据当前类对象逐层向上查找是否相等;


具体结果分析:1. person的类对象和NSObject类对象比较,不相等;然后Person的父类NSObject的类对象与NSObject类对象比较,则相等;

[person isKindOfClass:[NSObject class]]; //打印结果: 1

2. person的类对象和Person类对象比较,则相等;

[person isKindOfClass:[Person class]]; //打印结果: 1

3. person的类对象与NSObject的类对象比较,不相等;

[person isMemberOfClass:[NSObject class]]; //打印结果: 0

4. person的类对象和Person类对象比较,则相等;

[person isMemberOfClass:[Person class]]; //打印结果: 1

5. NSObject的元类对象与NSObject类对象比较,不相等;由于NSObject的元类对象最终又指向了NSObject类对象再次与NSObject类对象比较,则相等;参考前文

[[NSObject class] isKindOfClass:[NSObject class]]; //打印结果: 1

6. NSObject的元类对象与NSObject类对象比较,则不相等;

[[NSObject class] isMemberOfClass:[NSObject class]]; //打印结果: 0

7. Person的元类对象与Person类对象比较,则不相等;继续向上查找,最终也不相等;

[[Person class] isKindOfClass:[Person class]]; //打印结果: 0

8. Person的元类对象与Person类对象比较,则不相等

[[Person class] isMemberOfClass:[Person class]]; //打印结果: 0

9. Person的元类对象NSObject类对象比较,不相等;然后NSObject的元类对象与NSObject类对象比较,不相等;然后NSObject类对象与NSObject类对象比较,故相等;

[[Person class] isKindOfClass:[NSObject class]]; //打印结果: 1

本文部分内容来可能来源于网络,发布的内容如果侵犯了您的权益,请联系我们尽快删除!

相关文章
定义类,super的使用,super的使用
要求: a.需要有一个类变量 b.需要有>=2个的对象变量 c.定义一个方法:打印类变量和对象变量 d.使用print打印对象->输出为This is a object e.实例化两个对象:且两个对象相加等于2 f.为对象添加一个临时变量temp_var
54 0
|
Java
关键字super
关键字super
60 0
|
Java
关键字:super
关键字:super
60 0
|
Java Android开发
构造器里面的super()有什么用?到底写不写?
平时写的单独一个类如果没有直接继承父类就是直接继承的Object,有父类就是间接继承的Object,因为父类会继承Object,java的所有类都是Object的子类,哪怕不写super(),也会默认调用的父类的空构造器。
112 0
Java语法:super 详解
学习super时,应该和this对比着学习,以达到事半公倍的效果
387 0
this和super用法的区别与细节(java继承中this和super的比较)
this和super用法的区别与细节(java继承中this和super的比较)
|
Java 编译器
super&this
类在继承时会用到this和super,this通常指当前对象,super则指父类的。
274 0