1. 类定义
1.1 LGPerson类定义
@interface LGPerson : NSObject
- (void)sayHello;
+ (void)sayHappy;
@end
1.2 关于类的归属的测试题
#ifdef DEBUG
#define LGLog(format, ...) printf("%s\n", [[NSString stringWithFormat:format, ## __VA_ARGS__] UTF8String]);
#else
#define LGLog(format, ...);
#endif
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);
//Method, name: sayHello
}
free(methods);
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method *metalMethods = class_copyMethodList(metaClass, &count);
for (unsigned int i=0; i < count; i++) {
Method const metalMethod = metalMethods[i];
//获取方法名
NSString *key = NSStringFromSelector(method_getName(metalMethod));
LGLog(@"metal Method, name: %@", key);
//metal Method, name: sayHappy
}
free(metalMethods);
}
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));
//lgInstanceMethod_classToMetaclass - 0x1000031b0-0x0-0x0-0x100003148
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);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
//- (void)sayHello;
//+ (void)sayHappy;
// 元类 为什么有 sayHappy 类方法 0 1
/*
class_getClassMethod的底层是获取元类的class_getInstanceMethod方法。
class_getInstanceMethod(cls->getMeta(),sel)
如果当前的类cls是元类,则cls->getMeta()接返回cls
在当前类(元类)cls中可以找到找到实例方法sayHappy
*/
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
//lgClassMethod_classToMetaclass-0x0-0x0-0x100003148-0x100003148
LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
void lgIMP_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
// - (void)sayHello;
// + (void)sayHappy;
/*
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
// Translate forwarding function to C-callable external version
if (!imp) {
return _objc_msgForward; //没有找到方法实现,返回_objc_msgForward函数指针
}
return imp;
}
*/
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello)); //对象方法存储在类中
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello)); //没有找到方法实现,返回_objc_msgForward函数指针
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy)); //没有找到方法实现,返回_objc_msgForward函数指针 可以通过断点后打印 p imp3 查看 **(IMP) $0 = 0x7fff71092580 (libobjc.A.dylib`_objc_msgForward)**
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy)); //类方法存储在元类中
//lgIMP_classToMetaclass-0x100001d10-0x7fff71092580-0x7fff71092580-0x100001d40
NSLog(@"%s-%p-%p-%p-%p",__func__,imp1,imp2,imp3,imp4);
}
void isKind_MemberOfClass(){
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]]; //1,0,0,0
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]]; //1,1,1,1
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
lgObjc_copyMethodList(pClass);
lgInstanceMethod_classToMetaclass(pClass);
lgClassMethod_classToMetaclass(pClass);
lgIMP_classToMetaclass(pClass);
}
return 0;
}
2.问题解析
2.1 通过runtime的 class_copyMethodList获取方法列表验证方法的归属问题
- 获取对象方法列表
对象方法:存放在类中,归属于类
unsigned int count = 0;
Method *methods = class_copyMethodList(pClass, &count);
- 获取类方法列表
类方法:存放在元类,归属于元类,类是元类的实例
unsigned int count = 0;
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method *metalMethods = class_copyMethodList(metaClass, &count);
2.2 class_getInstanceMethod:分别在类和元类中找实例方法
对象方法:是类的实例方法,类方法:是元类的实例方法
class_getInstanceMethod(pClass,@selector(sayHappy))
class_getInstanceMethod(metalClass,@selector(sayHappy))
- 类方法归属于
元类,在类中获取实例方法,找不到类方法+sayHappy 类是元类的实例,在元类中获取实例方法,可以找到类方法+sayHappy
class_getInstanceMethod(pClass,@selector(sayHello))
class_getInstanceMethod(metalClass,@selector(sayHello))
- 实例方法归属于
类,在类中获取实例方法,可以到实例方法-sayHello 类是元类的实例,在元类中获取实例方法,找不到实例方法-sayHello
2.3 class_getClassMethod 分别在类和元类中找类方法
class_getClassMethod(pClass, @selector(sayHello));
class_getClassMethod(metaClass, @selector(sayHello))
- 实例方法归属于
类,在类中获取类方法,找不到实例方法-sayHello - 在
元类中获取类方法,找不到实例方法-sayHello
class_getClassMethod(pClass, @selector(sayHappy));
class_getClassMethod(metaClass, @selector(sayHappy));
- 类方法归属于
元类,在类中获取类方法,可以找到类方法+sayHappy - 在
元类中获取类方法,需要查看class_getClassMethod的底层实现class_getClassMethod的底层是获取元类的class_getInstanceMethod方法。class_getInstanceMethod(cls->getMeta(),sel) 如果当前的类cls是元类,则cls->getMeta()不会继续往根元类递归,直接返回cls,在当前类(元类)cls中可以找到找到实例方法sayHappy
通过isa的走位图,可知根元类的isa指向自己,如果元类查找类方法一直递归查找当前类的元类的实例方法,那么递归到根元类后会陷入死循环,所以OC底层在递归的时候,会判断当前类,如果当前类为元类,则不会继续递归,直接返回当前的类,在当前类(即元类)中查找实例方法;
3 isKindOfClass和isMemberOfClass
3.1 +isKindOfClass:从元类开始,递归父类,查询是否等于cls
- 3.1.1 函数原型
+ (BOOL)isKindOfClass:(Class)cls {
//从当前类的元类开始,递归父类,查询是否等于cls
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
//llvm底层优化: Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();
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);
}
- 3.1.2 面试题
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
-
- NSObject元类==NSObject--NO
-
- NSObject元类的父类(根元类) == NSObject --NO
-
- 根元类的父类(NSObject,即根类) == NSObject -- YES =>返回YES
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]
-
- LGPerson元类==LGPerson--NO
-
- LGPerson元类的父类(NSObject的元类,即根元类) == LGPerson --NO
-
- 根元类的父类(NSObject,即根类) == LGPerson --NO
-
- 根类的父类 == nil 递归结束 => 返回NO
3.2 -isKindOfClass:从self的当前类开始,递归父类,查询是否等于cls
- 3.2.1 函数原型:
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- 3.2.2 面试题
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
// NSObject==NSObject--YES
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];
//LGPerson==LGPerson--YES
3.3 +isMemberOfClass 判断元类是否等于cls
- 3.3.1 函数原型
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- 3.3.2 面试题
//+isMemberOfClass:判断元类是否等于cls
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //NSObject元类(根元类) == NSObject --NO
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];//LGPerson元类==LGPerson--NO
3.4 -isMemberOfClass 判断self的类是否等于cls
- 3.4.1 函数原型
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- 3.4.2 面试题
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; // NSObject == NSObject -- YES
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; //LGPerson == LGPerson -- YES