面试题如下

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

[NSObject class]的本质就是类对象,所以以上写法等同于如下写法

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

打印结果

[NSObject isKindOfClass:[NSObject class]]=1
[NSObject isMemberOfClass:[NSObject class]]=0
[DXPerson isKindOfClass:[DXPerson class]]=0
[DXPerson isMemberOfClass:[DXPerson class]0

为啥结果跟预期的想法视乎不一致,先看以下题目

id person = [[DXPerson alloc] init];

NSLog(@"%d", [person isMemberOfClass:[DXPerson class]]);
NSLog(@"%d", [person isMemberOfClass:[NSObject class]]);

NSLog(@"%d", [person isKindOfClass:[DXPerson class]]);
NSLog(@"%d", [person isKindOfClass:[NSObject class]]);


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

它们的底层实现

#import <objc/runtime.h>
// 同理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;
}
// 同理isKindOfClass
+ (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;
}

总结:

// 这句代码的方法调用者不管是哪个类(只要是NSObject体系下的),都返回YES
NSLog(@"%d", [NSObject isKindOfClass:[NSObject class]]);

再看以下面试题,给NSObject写一个分类,声明一个实例方法,一个类方法,仅仅实现实例方法

@interface NSObject (Interview)
+ (void)foo;
- (void)foo;
@end

@implementation NSObject (Interview)
- (void)foo{
    NSLog(@"- (void)foo");
}
@end

那么调用,NSObject类方法,会发生崩溃?

[NSObject foo];

答案是不会发生崩溃,而且调用了对象方法.

原理:

根据消息机制,会先在元类查找foo方法,没找到,NSObject会一层一层往上查找tcls = tcls->superclass,最终NSObject元类通过superclass会找到NSObject类对象,类对象存储着对象方法,正是foo方法,于是就找到

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

demo

如果反过来,仅仅实现类方法

@implementation NSObject (Interview)
+ (void)foo{
    NSLog(@"+ (void)foo");
}
@end

那么调用这个实例方法,会不会崩溃?

NSObject *obj = [NSObject new];
[obj foo];

答案很明显,会崩溃

-[NSObject foo]: unrecognized selector sent to instance 0x102001750
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NSObject foo]: unrecognized selector sent to instance 0x102001750'