id和Class的定义
runtime里面,声明了id和Class的类型,简化一下如下:
struct objc_class {
struct objc_class *isa;
};
struct objc_object {
struct objc_class *isa;
};
// (class object)
typedef struct objc_class *Class;
// (instance of class)
typedef struct objc_object *id;
在objc中,id代表了一个对象。根据上面的声明,凡是首地址是*isa的struct指针,都可以被认为是objc中的对象。运行时可以通过isa指针,查找到该对象是属于什么类(Class)。
如果一个类:
@interface Test : NSObject {
int age;
NSString *name;
}
- (void)myAge;
+ (void)myName;
@end
@implementation Test
- (void)myAge {
printf("instance");
}
+ (void)myName {
printf("class");
}
@end
clang -rewrite-objc Test.m
会出现这些内容(只是一部分)
//Class的实际结构
struct _class_t {
struct _class_t *isa; //isa指针
struct _class_t *superclass; //父类
void *cache;
void *vtable;
struct _class_ro_t *ro; //Class包含的信息
};
//Class包含的信息
struct _class_ro_t {
unsigned int flags;
unsigned int instanceStart;
unsigned int instanceSize;
unsigned int reserved;
const unsigned char *ivarLayout;
const char *name; //类名
const struct _method_list_t *baseMethods; //方法列表
const struct _objc_protocol_list *baseProtocols; //协议列表
const struct _ivar_list_t *ivars; //ivar列表
const unsigned char *weakIvarLayout;
const struct _prop_list_t *properties; //属性列表
};
//Test(meta-class)
struct _class_t OBJC_METACLASS_$_Test = {
.isa = &OBJC_METACLASS_$_NSObject,
.superclass = &OBJC_METACLASS_$_NSObject,
.cache = (void *)&_objc_empty_cache,
.vtable = (void *)&_objc_empty_vtable,
.ro = &_OBJC_METACLASS_RO_$_Test, //包含了类方法等
};
//Test(Class)
struct _class_t OBJC_CLASS_$_Test = {
.isa = &OBJC_METACLASS_$_Test, //此处isa指向meta-class
.superclass = &OBJC_CLASS_$_NSObject,
.superclass = (void *)&_objc_empty_cache,
.vtable = (void *)&_objc_empty_vtable,
.ro = &_OBJC_CLASS_RO_$_Test, //包含了实例方法 ivar信息等
};
所有实例的isa都指向了(Class)。
(Class)是一个全局变量,其中记录了类名、成员变量信息、property信息、protocol信息和实例方法列表等。
(Class)的isa指向了全局变量(meta-class),meta-class里只记录了类名、类方法列表等。
Test *test = [[Test alloc] init];
[Test myAge];
向(instance) 发送消息myAge时,运行时会通过isa指针查找到(Class),这里保存着本类中定义的实例方法的指针。
[Test myName];
向(Class)发送消息myName时,运行时会通过isa查找到(meta-class),这里保存着本类中定义的类方法的指针。
继承的话,大概是这样的:
Test *test = [[Test alloc] init];
Class cls = object_getClass(Test); //(Class)
class_getName(cls); //"Test"
class_isMetaClass(cls); //NO
Class meta = object_getClass(cls); //(meta-class)
class_getName(meta); //"Test"
class_isMetaClass(cls); //YES
Class meta_meta = object_getClass(meta); //NSObject(meta-class)
class_getName(meta_meta); //"NSObject"
class_isMetaClass(meta_meta); //YES
}