实例方法和类方法浅析
- 代码片段
void lgObjc_copyMethodList(Class pClass){
unsigned int count = 0;
Method *methods = class_copyMethodList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Method const method = methods[i];
//获取方法名
NSString *key = NSStringFromSelector(method_getName(method));
LGLog(@"Method, name: %@", key);
}
free(methods);
}
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
lgObjc_copyMethodList(pClass);
打印结果:
Method, name: sayHello
结论:实例方法存在类对象中,类方法存在元类对象中
- 代码片段
void lgInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
/// - (void)sayHello;
/// + (void)sayHappy;
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);
}
void lgClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
/// - (void)sayHello;
/// + (void)sayHappy;
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s - %p - %p - %p - %p",__func__,method1,method2,method3,method4);
}
其结果为:
lgInstanceMethod_classToMetaclass - 0x100003358 - 0x0 - 0x0 - 0x1000032f0
lgClassMethod_classToMetaclass - 0x0 -0x0 - 0x1000032f0 - 0x1000032f0
分析:
for (unsigned attempts = unreasonableClassCount();;) {
// curClass method list.
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
imp = meth->imp;
goto done;
}
if (slowpath((curClass = curClass->superclass) == nil)) {
// No implementation found, and method resolver didn't help.
// Use forwarding.
imp = forward_imp;
break;
}
// Halt if there is a cycle in the superclass chain.
if (slowpath(--attempts == 0)) {
_objc_fatal("Memory corruption in class list.");
}
// Superclass cache.
imp = cache_getImp(curClass, sel);
if (slowpath(imp == forward_imp)) {
// Found a forward:: entry in a superclass.
// Stop searching, but don't cache yet; call method
// resolver for this class first.
break;
}
if (fastpath(imp)) {
// Found the method in a superclass. Cache it in this class.
goto done;
}
}
class_getInstanceMethod当前类或者父类没有该实例方法就会返回NULL
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
class_getClassMethod当前类或者父类没有该类方法就会返回NULL
第一个0x100003358:pClass是LGPerson,当前LGPerson类存在sayHello实例方法。
第二个0x0:metaClass是LGPerson类的元类,LGPerson类的元类不存在sayHello实例方法。按走位图继续查找根元类(NSObject)->根类(NSObject)->nil,都没有sayHello,最终返回NULL。
第三个0x0:pClass是LGPerson类,当前LGPerson类不存在sayHappy实例方法。按走位图继续查找根类(NSObject)->nil,都没有sayHello,最终返回NULL。
第四个0x1000032f0:metaClass是LGPerson类的元类,LGPerson类的元类存在sayHappy实例方法。对于LGPerson类的元类来说,sayHappy是一个实例方法。
第五个0x0:pClass是LGPerson类,pClass不是元类,则取LGPerson的元类,当前LGPerson的元类不存在sayHello方法。按走位图继续查找根元类(NSObject)-->根类(NSObject)->nil,都没有sayHello类方法,最终返回NULL。
第六个0x0:metaClass是LGPerson类的元类,当前LGPerson类的元类不存在sayHello方法。按走位图继续查找根元类(NSObject)->根类(NSObject)->nil,都没有sayHello类方法,最终返回NULL。
第七个0x1000032f0:pClass是LGPerson类,pClass不是元类,则取LGPerson的元类,当前LGPerson元类存在sayHappy类方法。
第八个0x1000032f0:metaClass是LGPerson类的元类,当前LGPerson元类存在sayHappy类方法。
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
re5 :1
re6 :1
re7 :1
re8 :1
查看 +isKindOfClass +isKindOfMember源码
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
依次遍历元类-->根元类-->根类-->nil,判断是否跟传入的cls相等
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
判断元类是否跟传入的cls相等
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
依次遍历对象的类-->父类-->根类-->nil,判断是否跟传入的cls相等
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
判断对象的类是否跟传入的cls相等
re1 :1 依次遍历元类NSObject-->根元类NSObject-->根类NSObject(此处相等)-->nil,判断是否跟传入的NSObject相等。
re2 :0 判断NSObject元类是否跟传入的NSObject根类相等。NSObject元类 != NSObject
re3 :0 依次遍历LGPerson元类-->NSObject根元类-->NSObject根类-->nil,判断是否跟传入的LGPerson相等。
re4 :0 判断LGPerson元类是否跟传入的LGPerson相等。LGPerson元类 != LGPerson
re5 :1 依次遍历NSObject类-->nil,判断是否跟传入的NSObject相等
re6 :1 判断NSObject类是否跟传入的NSObject相等
re7 :1 依次遍历LGPerson-->NSObject父类-->NSObject根类-->nil,判断是否跟传入的LGPerson相等
re8 :1 判断LGPerson是否跟传入的LGPerson相等
网友评论