OC底层探索(六) isa 经典面试题分析

OC底层探索(六)关于isa走位图的面试题

问题一:执行class_getInstanceMethod、class_getClassMethod和class_getMethodImplementation打印出什么?

Person.h文件

- (void)sayHello;
+ (void)sayHappy;

Main.h文件

const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass,@selector(sayHello));
    Method method2 = class_getInstanceMethod(metaClass,@selector(sayHello));

    Method method3 = class_getInstanceMethod(pClass,@selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass,@selector(sayHappy));

Method method5 = class_getClassMethod(pClass, @selector(sayHello));
    Method method6 = class_getClassMethod(metaClass,@selector(sayHello));

    Method method7 = class_getClassMethod(pClass, @selector(sayHappy));
Method method8 = class_getClassMethod(metaClass,@selector(sayHappy));

IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
    IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));

    IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
    IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));

NSLog(@"%p-%p-%p-%p",method1 ,method2 ,method3 ,method4 );
NSLog(@"%p-%p-%p-%p",method5 ,method6 ,method7 ,method8 );
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);

请问打印输出什么?

源码分析

class_getInstanceMethod 源码

分析

  • 获取当前类实例方法SEL。

问题分析

1.Method method1 = class_getInstanceMethod(pClass,@selector(sayHello));

  • sayHello是LGPerson的实例方法,所以返回一个地址指针。

2. Method method2 = class_getInstanceMethod(metaClass,@selector(sayHello));

  • sayHello是LGPerson的实例方法,LGPerson元类中不存在,所以返回一个空指针。

3.Method method3 = class_getInstanceMethod(pClass,@selector(sayHappy));

  • sayHappy是LGPerson的类方法,不是LGPerson的实例方法,所以返回一个空指针。

4.Method method4 = class_getInstanceMethod(metaClass,@selector(sayHappy));

  • sayHappy是LGPerson的类方法,是LGPerson元类的实例方法,所以返回一个地址指针。

class_getClassMethod 源码

Method class_getClassMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return nil;

    return class_getInstanceMethod(cls->getMeta(), sel);
}

getMeta源码

 Class getMeta() {
        if (isMetaClass()) return (Class)this;
        else return this->ISA();
    }

分析

  • 当前类的元类是否存在实例方法SEL
  • 获取元类时,如果当前类是一个元类,那么返回当前类。

问题分析

1.Method method5 = class_getClassMethod(pClass, @selector(sayHello));

  • sayHello是LGPerson的实例方法;
  • LGPerson.getMeta() => LGPerson元类,其中不存在sayHello方法,所以返回空指针。

2.Method method6 = class_getClassMethod(metaClass,@selector(sayHello));

  • sayHello是LGPerson的实例方法;
  • LGPerson元类.getMeta() => LGPerson元类,其中不存在sayHello方法,所以返回空指针。

3.Method method7 = class_getClassMethod(pClass, @selector(sayHappy));

  • sayHappy是LGPerson的类方法;
  • LGPerson元类.getMeta() => LGPerson元类,其中存在sayHappy方法,所以返回一个指针。

4.Method method8 = class_getClassMethod(metaClass,@selector(sayHappy));

  • sayHappy是LGPerson的类方法;
  • LGPerson元类.getMeta() => LGPerson元类,其中存在sayHappy方法,所以返回一个指针。

class_getMethodImplementation源码

IMP class_getMethodImplementation(Class cls, SEL sel)
{
    IMP imp;

    if (!cls  ||  !sel) return nil;

    //查找方法实现
    imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);

    //如果没有找到,则进行消息转发
    if (!imp) {
        return _objc_msgForward;
    }

    return imp;
}

分析

  • lookUpImpOrNil中查找方法是否存在
  • 如果不存在,则进行消息转发

问题分析
1. IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));

  • LGPerson类存在实例方法sayHello,返回方法的地址指针。

    2. IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));

  • LGPerson元类不存在实例方法sayHello

  • 消息进行转发。

    3. IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));

  • LGPerson类不存在实例方法sayHappy

  • 消息进行转发

  • 4. IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));

  • LGPerson元类存在实例方法sayHappy,返回方法的地址指针。

问题二:isKindOfClass 与 isMemberOfClass的理解

 BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];       //
        BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     //
        BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];       //
        BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];     //
        NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

        BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];       //
        BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     //
        BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];       //
        BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];     //
        NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

请问打印输出什么?

源码分析

IskindOfClass源码:

由于iOSllvm中编译时,对isKindOfClass进行了优化处理,不管类方法+IskindOfClass还是实例方法-IskindOfClass都会执行objc_opt_isKindOfClass

BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
    //获取isa,
    //如果obj 是对象,则isa是类,
    //如果obj是类,则isa是元类
    Class cls = obj->getIsa(); 
    if (fastpath(!cls->hasCustomCore())) {
        // 如果obj 是对象,则在类的继承链进行对比,
        // 如果obj是类,则在元类的isa中进行对比
        for (Class tcls = cls; tcls; tcls = tcls->superclass) { 
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);

分析

  1. 如果传入的obj是类,获取当前类的ISA(元类) == 传入类cls ? true : 执行第三步;
  2. 如果传入的obj是对象,获取当前对象的类 == 传入类cls ? true : 执行第三步;
  3. 上次元类的父类 == 传入类cls ? true : false。

题目分析

1.[(id)[NSObject class] isKindOfClass:[NSObject class]];

  • NSObject的元类 => 根源类:根源类 != NSObject类;所以继续执行;
  • 根源类的父类 => NSObject类:NSObject类 == NSObject类,返回true。

2.[(id)[LGPerson class] isKindOfClass:[LGPerson class]];

  • LGPerson 的元类 => LGPerson 元类:LGPerson 元类 != LGPerson 类;所以继续执行;
  • LGPerson 元类的父类 => NSObject元类: NSObject元类 != LGPerson 类,返回false。

3.[(id)[NSObject alloc] isKindOfClass:[NSObject class]];

  • NSObject对象的类 => NSObject类: NSObject类 == NSObject类,返回true。

4.[(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];

  • LGPerson 对象的类 => LGPerson 类: LGPerson 类 == LGPerson 类,返回true。
类方法isMemberOfClass源码:
+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

分析

  • 当前类的ISA(元类) == cls相等 ? true : false。

题目分析

1.[(id)[NSObject class] isMemberOfClass:[NSObject class]];

  • NSObject类的元类=> 根源类:根源类 != NSObject类,返回false。

2.[(id)[LGPerson class] isMemberOfClass:[LGPerson class]];

  • LGPerson 类的元类=> LGPerson 元类:LGPerson 元类 != LGPerson 类,返回false。
实例方法isMemberOfClass
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}


分析

  • 当前对象的类 == 类cls ? true :false。

题目分析

1.[(id)[NSObject alloc] isMemberOfClass:[NSObject class]];

  • NSObject对象的类=> NSObject类:NSObject类 == NSObject类,返回true。

2.[(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];

  • LGPerson 对象的类=> LGPerson 类:LGPerson 类 == LGPerson 类,返回true。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值