1. class_getInstanceMethod 与 class_getClassMethod 分析
首先定义两个类和方法
@interface LGPerson : NSObject
- (void)sayHello;
+ (void)sayHappy;
@end
@implementation LGPerson
- (void)sayHello{
}
+ (void)sayHappy{
}
@end
@interface LGTeacher : NSObject
- (void)say666;
@end
@implementation LGTeacher
- (void)say666{
}
@end
测验代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
lgInstanceMethod_classToMetaclass(pClass);
lgClassMethod_classToMetaclass(pClass);
}
return 0;
}
/// 获取 InstanceMethod 方法
void lgInstanceMethod_classToMetaclass(Class pClass){
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));
LGLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
/// 获取 classMethod 方法
void lgClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
// 元类 为什么有 sayHappy 类方法 0 1
//
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
第一组打印结果 lgInstanceMethod_classToMetaclass - 0x1000081f8-0x0-0x0-0x100008190 结果显示method1
方法(LGPerson
类的实例方法
)和method4
(LGPerson元类
的类方法
)方法被找到。来,分析一波!
class_getInstanceMethod
方法实现
Method class_getInstanceMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
// This deliberately avoids +initialize because it historically did so.
// This implementation is a bit weird because it's the only place that
// wants a Method instead of an IMP.
#warning fixme build and search caches
// Search method lists, try method resolver, etc.
lookUpImpOrForward(nil, sel, cls, LOOKUP_RESOLVER);
#warning fixme build and search caches
return _class_getMethod(cls, sel);
}
_class_getMethod
方法源码实现
static Method _class_getMethod(Class cls, SEL sel)
{
mutex_locker_t lock(runtimeLock);
return getMethod_nolock(cls, sel);
}
getMethod_nolock
方法源码实现
static method_t *
getMethod_nolock(Class cls, SEL sel)
{
method_t *m = nil;
runtimeLock.assertLocked();
// fixme nil cls?
// fixme nil sel?
ASSERT(cls->isRealized());
while (cls && ((m = getMethodNoSuper_nolock(cls, sel))) == nil) {
cls = cls->superclass;
}
return m;
}
while
循环中关键指向cls = cls->superclass
,条件为 cls
存在并且method_t m
没有找到,再看下getMethodNoSuper_nolock
方法是怎么找的
static method_t *
getMethodNoSuper_nolock(Class cls, SEL sel)
{
runtimeLock.assertLocked();
ASSERT(cls->isRealized());
// fixme nil cls?
// fixme nil sel?
// class_rw_t ->methods()
auto const methods = cls->data()->methods();
for (auto mlists = methods.beginLists(),
end = methods.endLists();
mlists != end;
++mlists)
{
// getMethodNoSuper_nolock is the hottest
// caller of search_method_list, inlining it turns
// getMethodNoSuper_nolock into a frame-less function and eliminates
// any store from this codepath.
method_t *m = search_method_list_inline(*mlists, sel);
if (m) return m;
}
return nil;
}
其实就是通过cls
-> data()
-> methods()
找到方法列表循环遍历寻找。跟上篇 ISA指向、类结构通过lldb
分析方法存储位置相似,我们验证的结果是类的实例方法储存在该类中methods()方法中,类方法储存在该类的元类中,class_getInstanceMethod
方法流程就是通过 类
-> 父类
... -> 根类
的循环从data()
-> methods()
中循环遍历寻找,所以method2
、method4
是寻找不到的。
第二组打印结果:lgClassMethod_classToMetaclass-0x0-0x0-0x100008190-0x100008190
结果显示method3方法(LGPerson类的类方法)和method4(LGPerson元类的类方法)方法被找到。来,看源码!
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
class_getInstanceMethod
它又出现了,这次省事儿了,直接看 getMeta
方法。
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
class_getClassMethod
其实就是把当前传入类做了判断,如果传入的是元类
,走class_getInstanceMethod
遍历循环,传入的不是元类
,返回元类走class_getInstanceMethod
遍历循环。
2. 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);
第一组打印数据
re1 :1
re2 :0
re3 :0
re4 :0
开始分析
+ (BOOL)isKindOfClass:(Class)cls {
// 查找顺序 cls元类 ->父类 ->.... ->NSObject元类 ->NSObject
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
+ (BOOL)isMemberOfClass:(Class)cls {
// 元类和传入类做对比
return self->ISA() == cls;
}
第二组打印数据
re5 :1
re6 :1
re7 :1
re8 :1
再次分析
- (BOOL)isKindOfClass:(Class)cls {
// 查找顺序 当前对象的类 ->父类 ->... ->NSObject
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isMemberOfClass:(Class)cls {
// 对象的 class方法与传入类做对比,相当于类的实例对象的ISA()。
return [self class] == cls;
}
总结
isKindOfClass
方法与isMemberOfClass
不管类方法
还是实例方法
,都是对当前调用者的 isa指针
做对比,只是前者遍历
,后者不遍历
的区别。