首先认清一些概念。
struct objc_object {
Class isa;
};
typedef struct objc_object *id;
struct objc_class {
Class isa;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
};
typedef struct objc_class *Class;
此结构体可以储存类的诸多信息,例如类型名、父类类型、实例变量列表、方法列表等,这些信息被称作类的元数据(metadata)
。该结构体也有一个Class类型的成员isa,说明Class本身也是一个OC对象(被称为类对象或类型对象),而它的对象类型(isa所指向的类型)被称为元类(metaclass)
,元类中储存的是类对象的元数据,比如类方法就储存在这里。每个类可以有无数个对象,但仅有一个类对象,也仅有一个与之对应的元类。
object_getClass(obj)与[obj class]区别?
object_getClass(obj)返回的是obj中的isa指针;而[obj class]则分两种情况:一是当obj为实例对象时,[obj class]中class是实例方法:- (Class)class,返回的obj对象中的isa指针;二是当obj为类对象(包括元类和根类以及根元类)时,调用的是类方法:+ (Class)class,返回的结果为其本身。
Class f = object_getClass([sunClass superclass]);
Class g = object_getClass([[sunClass superclass] class]);
f == g
metaSunClass * sunClass = [[metaSunClass alloc] init];
Class a = object_getClass(object_getClass([sunClass class]));
Class b = object_getClass(object_getClass([[sunClass superclass] class]));
//此时 a == b 证明上图最右侧虚线元类的class是root[既:NSObject]。
下面的测试代码,是用来获取实例对象的方法和相应的元类方法,证明上图流程。
@interface metaBaseClass : NSObject {
NSInteger iNum;
}
@property (assign, nonatomic, readonly ) NSInteger uNum;
- (NSInteger) getINumber;
- (void) setINumber:(NSInteger) num;
+ (void)printILog;
+ (void)printIILog;
@end
@implementation metaBaseClass
- (NSInteger) getINumber {
return iNum;
}
- (void) setINumber:(NSInteger) num {
iNum = num;
}
+ (void)printILog {
NSLog(@"show log");
}
+ (void)printIILog {
NSLog(@"show II log");
}
@end
@interface metaSunClass : metaBaseClass {
NSInteger yNum;
}
@property (assign, nonatomic, readonly ) NSInteger uYNum;
- (NSInteger) getYNumber;
- (void) setYNumber:(NSInteger) num;
+ (void)printYLog;
@end
@implementation metaSunClass
- (NSInteger) getYNumber {
return yNum;
}
- (void) setYNumber:(NSInteger) num {
yNum = num;
}
+ (void)printILog {
NSLog(@"show Y log");
}
+ (void)printYLog {
NSLog(@"show YY log");
}
@end
Method * mm = class_copyMethodList([sunClass class], &count);
NSLog(@"%u",count);
for(int j =0; j < count; j++) {
Method mt = mm[j];
SEL sel =method_getName(mt);
NSString *strName = [NSString stringWithCString:sel_getName(sel)encoding:NSUTF8StringEncoding];
NSLog(@"%@",strName);
}
打印结果如下:
2016-05-16 20:17:03.698 test[17841:1055828] 3
2016-05-16 20:17:03.698 test[17841:1055828] getYNumber
2016-05-16 20:17:03.699 test[17841:1055828] setYNumber:
2016-05-16 20:17:03.699 test[17841:1055828] uYNum
Method * mm = class_copyMethodList([[sunClass superclass] class], &count);
NSLog(@"%u",count);
for(int j =0; j < count; j++) {
Method mt = mm[j];
SEL sel =method_getName(mt);
NSString *strName = [NSString stringWithCString:sel_getName(sel)encoding:NSUTF8StringEncoding];
NSLog(@"%@",strName);
}
2016-05-16 20:17:49.717 test[17863:1056796] 3
2016-05-16 20:17:49.717 test[17863:1056796] getINumber
2016-05-16 20:17:49.717 test[17863:1056796] setINumber:
2016-05-16 20:17:49.717 test[17863:1056796] uNum
Method * mm = class_copyMethodList(object_getClass([sunClassclass]), &count);
NSLog(@"%u",count);
for(int j =0; j < count; j++) {
Method mt = mm[j];
SEL sel =method_getName(mt);
NSString *strName = [NSString stringWithCString:sel_getName(sel)encoding:NSUTF8StringEncoding];
NSLog(@"%@",strName);
}
2016-05-16 20:19:21.936 test[17888:1058041] 2
2016-05-16 20:19:21.936 test[17888:1058041] printILog
2016-05-16 20:19:21.936 test[17888:1058041] printYLog
Method * mm = class_copyMethodList(object_getClass([[sunClasssuperclass]class]), &count);
//equal to Method * mm = class_copyMethodList(object_getClass([[sunClassclass]superclass]), &count);
NSLog(@"%u",count);
for(int j =0; j < count; j++) {
Method mt = mm[j];
SEL sel =method_getName(mt);
NSString *strName = [NSString stringWithCString:sel_getName(sel)encoding:NSUTF8StringEncoding];
NSLog(@"%@",strName);
}
2016-05-16 20:22:32.720 test[17930:1060301] 2
2016-05-16 20:22:32.720 test[17930:1060301] printILog
2016-05-16 20:22:32.720 test[17930:1060301] printIILog