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源码:
由于iOS在llvm中编译时,对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);
分析
- 如果传入的obj是类,获取当前类的ISA(元类) == 传入类cls ? true : 执行第三步;
- 如果传入的obj是对象,获取当前对象的类 == 传入类cls ? true : 执行第三步;
- 上次元类的父类 == 传入类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。