class_getInstanceMethod和class_getClassMethod
- 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);
}
-
查找方法流程图如下
image.png - search_method_list_inline内部会对排序过的方法列表二分查找,没排序的遍历查找
ALWAYS_INLINE static method_t *
search_method_list_inline(const method_list_t *mlist, SEL sel)
{
int methodListIsFixedUp = mlist->isFixedUp();
int methodListHasExpectedSize = mlist->entsize() == sizeof(method_t);
if (fastpath(methodListIsFixedUp && methodListHasExpectedSize)) {//如果是排序过的方法列表使用2分查找
return findMethodInSortedMethodList(sel, mlist);
} else {
// Linear search of unsorted method list
for (auto& meth : *mlist) {// 遍历查找
if (meth.name == sel) return &meth;
}
}
#if DEBUG
// sanity-check negative results
if (mlist->isFixedUp()) {
for (auto& meth : *mlist) {
if (meth.name == sel) {
_objc_fatal("linear search worked when binary search did not");
}
}
}
#endif
return nil;
}
- class_getClassMethod的源码实现
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
Class getMeta() {// 如果是元类返回自身,不是元类放回自身的isa也就是元类
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
- class_getInstanceMethod会从其类对象及其父类的方法列表中查找,class_getClassMethod会从元类对象及其元类父类的方法列表中查找方法。实例方法和类方法在类对象和元类对象中存储的形式是一样的。
- 通过一个例子来理解下上述的结论,新建一个Person类
@interface Person : NSObject
- (void)sayHello;
+ (void)say666;
@end
@implementation Person
- (void)sayHello{
NSLog(@"%s",__func__);
}
+ (void) say666{
NSLog(@"%s",__func__);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc] init];
Class pClass = object_getClass(p);
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(say666));
Method method4 = class_getInstanceMethod(metaClass, @selector(say666));
Method method5 = class_getClassMethod(pClass, @selector(sayHello));
Method method6 = class_getClassMethod(metaClass, @selector(sayHello));
Method method7 = class_getClassMethod(pClass, @selector(say666));
Method method8 = class_getClassMethod(metaClass, @selector(say666));
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
NSLog(@"%p-%p-%p-%p",method5,method6,method7,method8);
}
return 0;
}
- 上述代码打印结果为
2020-09-15 16:12:41.727544+0800 class_getMethod[3431:20892761] 0x1000020c0-0x0-0x0-0x100002058
2020-09-15 16:12:41.728234+0800 class_getMethod[3431:20892761] 0x0-0x0-0x100002058-0x100002058
isKindOfClass和isMemberOfClass
- 我们看看下面这段代码的打印结果
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re3 = [(id)[Person class] isKindOfClass:[Person class]];
BOOL re4 = [(id)[Person class] isMemberOfClass:[Person class]];
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL re7 = [(id)[Person alloc] isKindOfClass:[Person class]];
BOOL re8 = [(id)[Person alloc] isMemberOfClass:[Person class]];
NSLog(@"%d-%d-%d-%d",re1,re2,re3,re4);
NSLog(@"%d-%d-%d-%d",re5,re6,re7,re8);
}
return 0;
}
// 打印结果
2020-09-15 16:31:20.515562+0800 KCObjc[4756:20941428] 1-0-0-0
2020-09-15 16:31:20.516222+0800 KCObjc[4756:20941428] 1-1-1-1
- 直接查看isKindOfClass和isMemberOfClass的源码
+ (BOOL)isKindOfClass:(Class)cls {//调用class的元类或元类的父类是否等于cls
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isKindOfClass:(Class)cls {//调用对象的class或父类是否等于cls
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
------------------------------------------------------------------------------------------
+ (BOOL)isMemberOfClass:(Class)cls {//调用class的元类是否等于cls
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {//调用对象的class是否等于cls
return [self class] == cls;
}
- 通过源码调试发现外部调用isKindOfClass并不是走的上述的实现,而是走的objc_opt_isKindOfClass,应该是llvm编译器作了处理。
// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)//id表示调用者,otherClass表示传入的参数
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();//获取isa,根据传入的obj获取他的类或者元类
if (fastpath(!cls->hasCustomCore())) {
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);
}
- 有点特殊的是re1,[NSObject class]的元类为根元类,根元类的superClass指向NSObject类对象所以re1的结果为yes。
class方法
- class有对象方法和实例方法,对应的实现如下
+ (Class)class { //对象方法返回自身
return self;
}
- (Class)class {//实例方法返回isa,也就是类对象
return object_getClass(self);
}
Class object_getClass(id obj) //也可以通过这个方法获取元类
{
if (obj) return obj->getIsa();
else return Nil;
}
- 通过源码调试发现外部调用class方法的时候也不是走的上述方法而是进入了objc_opt_class
// Calls [obj class]
Class
objc_opt_class(id obj)
{
#if __OBJC2__
if (slowpath(!obj)) return nil;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
return cls->isMetaClass() ? obj : cls;
}
#endif
return ((Class(*)(id, SEL))objc_msgSend)(obj, @selector(class));
}
- 通过llvm代码可以看到编译器对一些方法进行了处理包括
原方法 | llvm处理后执行的方法 |
---|---|
allocWithZone | objc_allocWithZone |
alloc | objc_alloc |
new | objc_opt_new |
self | objc_opt_self |
class | objc_opt_class |
isKindOfClass | objc_opt_isKindOfClass |
respondsToSelector | objc_opt_respondsToSelector |
... | ... |
网友评论