iOS面试题

super、isKindOfClass、isMemberOfCl

2021-11-15  本文已影响0人  再好一点点
一. super作用

Person类

#import <Foundation/Foundation.h>
@interface Person : NSObject
@end

#import "Person.h"
@implementation Person
@end

Student类

#import "Person.h"
@interface Student : Person
@end

#import "Student.h"
#import <objc/runtime.h>

@implementation Student

- (instancetype)init
{
    if (self = [super init]) {
        NSLog(@"[self class] = %@", [self class]); // Student
        NSLog(@"[self superclass] = %@", [self superclass]); // Person

        // objc_msgSendSuper({self, [Person class]}, @selector(class));
        NSLog(@"[super class] = %@", [super class]); // Student
        NSLog(@"[super superclass] = %@", [super superclass]); // Person
    }
    return self;
}

@end

将OC代码转成C/C++代码可以看到[super class]等于objc_msgSendSuper({self, [Person class]}, @selector(class));

结合上述打印结果可以有如下结论:

  1. [super message]objc_msgSendSuper(...)的底层实现
    a) 消息接收者仍然是子类对象
    b) 从父类开始查找方法的实现
    因此可以知道[super message]的消息接收者(调用者)还是self,只不过是从父类的方法列表开始查找方法而已。
二. isKindOfClass、isMemberOfClass

以下几个log的结果是什么?

NSLog(@"%d", [[NSObject class] isKindOfClass:[NSObject class]]);
NSLog(@"%d", [[NSObject class] isMemberOfClass:[NSObject class]]);
NSLog(@"%d", [[Person class] isKindOfClass:[Person class]]);
NSLog(@"%d", [[Person class] isMemberOfClass:[Person class]]);

//上边等同于下边
NSLog(@"%d", [NSObject isKindOfClass:[NSObject class]]); // 1
NSLog(@"%d", [NSObject isMemberOfClass:[NSObject class]]); // 0
NSLog(@"%d", [Person isKindOfClass:[Person class]]); // 0
NSLog(@"%d", [Person isMemberOfClass:[Person class]]); // 0

猛一看这几个结果可能会有点蒙,需要分析isKindOfClass、isMemberOfClass的具体含义才可以弄明白以上结果。
通过objc源码可以查看到以上两个方法的具体实现。分别有实例方法和类方法。

- (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;
}


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


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

a) - (BOOL)isMemberOfClass:(Class)cls直接拿到实例的类对象和传入的cls比较是否相等。
b) - (BOOL)isKindOfClass:(Class)cls使用传入的cls和实例的类对象或者父类比较(父类仍是类对象)。
c) + (BOOL)isMemberOfClass:(Class)cls使用元类对象和传入的cls比较是否相等。
d) + (BOOL)isKindOfClass:(Class)cls使用传入的cls和元类对象或者父类比较(父类仍是元类对象)。

通过上边对每个方法的具体的介绍可以做具体分析了,首先第一个:

  1. [[NSObject class] isKindOfClass:[NSObject class]]就是拿到NSObject这个类对象的元类对象和[NSObject class]比较,左边是NSObject元类对象,右边是NSObject类对象肯定不同,这时候继续循环比较,左边通过superclass找到NSObject这个元类对象的父类就是NSObject类对象,这个时候左右都是NSObject的类对象所以相同,返回YES。
  2. [[NSObject class] isMemberOfClass:[NSObject class]]就是拿到NSObject这个类对象的元类对象和[NSObject class]比较,左边是NSObject元类对象,右边是NSObject类对象肯定不同,返回NO。
  3. [[Person class] isKindOfClass:[Person class]]通过循环遍历左边Person元类对象的的父类分别为NSObject元类对象、NSObject类对象,右边为Person类对象,所以都不相同,返回NO。
  4. [[Person class] isMemberOfClass:[Person class]]拿到Person类对象的元类对象和[Person class]比较,左边为Person元类对象,右边为Person类对象,所以不相同,返回NO。
上一篇下一篇

猜你喜欢

热点阅读