备注:文章主要学习自飘飘白云的博客
Object & Class & Meta Class
objc中 class 与 object 的定义:
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
Class 是一个 objc_class 结构类型的指针;而 id(任意对象) 是一个 objc_object 结构类型的指针,其第一个成员是一个 objc_class 结构类型的指针。注意这里有一关键的引申解读:内存布局以一个 objc_class 指针为开始的所有东东都可以当做一个 object 来对待!
那 objc_class 又是怎样一个结构体呢?且看:
struct objc_class{
struct objc_class* isa;
struct objc_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;
};
类之间的关系
规则一:类的实例对象的 isa 指向该类;该类的 isa 指向该类的 metaclass;
规则二:类的 super_class 指向其父类,如果该类为根类则值为 NULL;
规则三:metaclass 的 isa 指向根 metaclass,如果该 metaclass 是根 metaclass 则指向自身;
规则四:metaclass 的 super_class 指向父 metaclass,如果该 metaclass 是根 metaclass 则指向该 metaclass 对应的类;
无图无真相!
那么 class 与 metaclass 有什么区别呢?
class 是 instance object 的类类型。当我们向实例对象发送消息(实例方法)时,我们在该实例对象的 class 结构的 methodlists 中去查找响应的函数,如果没找到匹配的响应函数则在该 class 的父类中的 methodlists 去查找(查找链为上图的中间那一排)。如下面的代码中,向str 实例对象发送 lowercaseString 消息,会在 NSString 类结构的 methodlists 中去查找 lowercaseString 的响应函数。
metaclass 是 class object 的类类型。当我们向类对象发送消息(类方法)时,我们在该类对象的 metaclass 结构的 methodlists 中去查找响应的函数,如果没有找到匹配的响应函数则在该 metaclass 的父类中的 methodlists 去查找(查找链为上图的最右边那一排)。如下面的代码中,向 NSString 类对象发送 stringWithString 消息,会在 NSString 的 metaclass 类结构的 methodlists 中去查找 stringWithString 的响应函数。
练习
下面的代码输出什么?
@implementation Dog : Animal
- (instancetype)init{
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
runtime中- (Class)class方法实现如下
- (Class)class {
return object_getClass(self);
}
runtime中+ (Class)class方法实现如下
+ (Class)class {
return self;
}
打印结果: 都输出Dog
2016-06-22 21:11:22.451 RuntimeTest[969:29418] IMP: -[NSObject(Animal) run]
2016-06-22 21:11:22.452 RuntimeTest[969:29418] IMP: -[NSObject(Animal) run]
问: 为什么?
下面的代码输出什么?
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [[Animal class] isKindOfClass:[Animal class]];
BOOL res4 = [[Animal class] isMemberOfClass:[Animal class]];
Animal *animal = [[Animal alloc] init];
BOOL res5 = [animal class] == [Animal class];
BOOL res6 = [animal isKindOfClass:[Animal class]];
BOOL res7 = [animal isMemberOfClass:[Animal class]];
NSLog(@"%d %d %d %d %d %d %d", res1, res2, res3, res4, res5, res6, res7);
runtime中isKindOfClass实现如下
- (BOOL)isKindOf:aClass
{
Class cls;
for (cls = isa; cls; cls = cls->superclass)
if (cls == (Class)aClass)
return YES;
return NO;
}
isMemberOfClass实现如下
- (BOOL)isMemberOf:aClass
{
return isa == (Class)aClass;
}
打印输出:
2016-06-22 21:15:13.840 RuntimeTest[987:31071] 1 0 0 0 1 1 1
问: 为什么?
下面的代码输出什么
@interface NSObject (Animal)
+ (void)run;
@end
@implementation NSObject (Animal)
- (void)run
{
NSLog(@"IMP: -[NSObject(Animal) run]");
}
@end
[NSObject run];
[[NSObject new] run];
打印输出:
2016-06-22 21:19:31.619 RuntimeTest[997:33664] IMP: -[NSObject(Animal) run]
2016-06-22 21:19:31.620 RuntimeTest[997:33664] IMP: -[NSObject(Animal) run]
问:为什么?