浅析class 、superclass、isMemberOfClass、isKindOfClass

经典图

浅析class 、superclass、isMemberOfClass、isKindOfClass_第1张图片

抛出问题

        BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
        BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
        BOOL res3 = [(id)[Student class] isKindOfClass:[Student class]];
        BOOL res4 = [(id)[Student class] isMemberOfClass:[Student class]];
        BOOL res5 = [student isKindOfClass:[Student class]];
        NSLog(@"%d %d %d %d %d", res1, res2, res3, res4, res5);

        打印:1 0 0 0 1

 先上内部方法实现

+ (Class)class {
    return self;
}

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

+ (Class)superclass {
    return self->superclass;
}

- (Class)superclass {
    return [self class]->superclass;
}

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

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


/***********************************************************************
* object_getClass.
* Locking: None. If you add locking, tell gdb (rdar://7516456).
**********************************************************************/
Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
  Student *obj = [[Student alloc]init];
        
        NSLog(@"instance         :%p", obj);
        NSLog(@"class            :%p", object_getClass(obj));
        NSLog(@"meta class       :%p", object_getClass(object_getClass(obj)));
        NSLog(@"root meta        :%p", object_getClass(object_getClass(object_getClass(obj))));
        NSLog(@"root meta's meta :%p", object_getClass(object_getClass(object_getClass(object_getClass(obj)))));


//打印
2019-08-19 13:18:18.516791+0800 Interview03-Category[1457:61373] instance         :0x100763390
2019-08-19 13:18:18.517043+0800 Interview03-Category[1457:61373] class            :0x1000039d8
2019-08-19 13:18:18.517059+0800 Interview03-Category[1457:61373] meta class       :0x1000039b0
2019-08-19 13:18:18.517072+0800 Interview03-Category[1457:61373] root meta        :0x7fffac7e80f0
2019-08-19 13:18:18.517084+0800 Interview03-Category[1457:61373] root meta's meta :0x7fffac7e80f0

首先我们看到实例对象的class方法返回的是实例对象对应的类对象,类对象的class方法返回的是类对象自己,实例对象的superclass方法返回的是实例对象对应的类对象的父类(也是个类对象),类对象的superclass返回的是类对象的父类,所以,一般情况下class的实例方法与类方法返回的是一样的类型,同理与superclass也是这样。

 

 

在isKindOfClass中有一个循环,先判断class是否等于meta class,不等就继续循环判断是否等于meta class的super class,不等再继续取super class,如此循环下去。

[NSObject class]执行完之后调用isKindOfClass,第一次判断先判断NSObject和 NSObject的meta class是否相等,之前讲到meta class的时候放了一张很详细的图,从图上我们也可以看出,NSObject的meta class与本身不等。接着第二次循环判断NSObject与meta class的superclass是否相等。还是从那张图上面我们可以看到:Root class(meta) 的superclass就是 Root
class(class),也就是NSObject本身。所以第二次循环相等,于是第一行res1输出应该为YES。

同理,[Student class]执行完之后调用isKindOfClass,第一次for循环,Sark的Meta Class与[Student class]不等,第二次for循环,Sark Meta Class的super class 指向的是 NSObject Meta Class, 和Student Class不相等。第三次for循环,NSObject Meta Class的super class指向的是NSObject Class,和 Student Class 不相等。第四次循环,NSObject Class 的super class 指向 nil, 和 Student Class不相等。第四次循环之后,退出循环,所以第三行的res3输出为NO。

所以:isKindOfClass方法的调用是调用者如果是实例,那么就拿该实例对应的类对象以及类对象的父类与传入的参数进行比较,如果调用者是类对象,那么就拿该类对象对应的元类对象与传入的参数进行比较。比如:

 BOOL res3 = [(id)[MJStudent class] isKindOfClass:object_getClass([MJStudent class])];

返回为YES。 

isMemberOfClass的源码实现是拿到自己的isa指针和传入的参数比较,相比于isKindOfClass少了tcls->superclass往父类查询比较的步骤。

你可能感兴趣的:(iOS)