Objective-C中的对象,简称OC对象,主要可以分为3种
instance对象(实例对象) class对象(类对象) meta-class对象(元类对象)instanceinstance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
代码语言:javascript代码运行次数:0运行复制NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
NSLog(@"%p", obj1);
NSLog(@"%p", obj2);打印结果会输出
代码语言:javascript代码运行次数:0运行复制0x1004992a0
0x1004974f0由此可以看出,obj1和obj2是两个不同的对象,分别占据着两块不同的内存。
而instance对象在内存中存储的信息包括
isa指针成员变量的值_age = 5,这个5就是存在于实例对象中的Class 对象查看以下代码中的内存地址
代码语言:javascript代码运行次数:0运行复制NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = [NSObject class];
Class objectClass4 = object_getClass(object1);
Class objectClass5 = object_getClass(object2);在控制台调试打印地址
代码语言:javascript代码运行次数:0运行复制(lldb) p/x (long)objectClass1
(long) $2 = 0x00007fff8a20f140
(lldb) p/x (long)objectClass2
(long) $3 = 0x00007fff8a20f140
(lldb) p/x (long)objectClass3
(long) $4 = 0x00007fff8a20f140
(lldb) p/x (long)objectClass4
(long) $5 = 0x00007fff8a20f140
(lldb) p/x (long)objectClass5
(long) $6 = 0x00007fff8a20f140经过调试可以发现5个Class类指向同一个地址值0x00007fff8a20f140,它和instance对象的区别是instance对象是alloc分配的内存空间,每个实例对象都占用不同的空间,但是Class一个类只占用一份内存空间。
objectClass1~objectClass5都是NSObject的Class对象(类对象)它们是同一个对象,每个类在内存中只有一个Class对象 Class对象在内存中存储的信息主要包括 isa指针 superclass指针类的属性信息(@property) 类的对象方法信息(instance method) 类的协议信息(protocol) 类的成员变量信息(ivar) meta-classclass和meta-class内存地址值比较
代码语言:javascript代码运行次数:0运行复制Class objectClass = [NSObject class];
Class objectMetaClass = object_getClass([NSObject class]);
NSLog(@"%p", objectClass);
NSLog(@"%p", objectMetaClass);代码语言:javascript代码运行次数:0运行复制0x7fff8a20f140
0x7fff8a20f0f0对比发现,Class和meta-class的内存地址不一样。我们可以进行如下总结 :
objectMetaClass是NSObject的meta-class对象(元类对象)每个类在内存中有且只有一个meta-class对象 meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存总存储的主要信息包括 isa指针 superclass指针类的类方法信息(class method) 注意获取元类的内存地址只能通过object_getClass([NSObject class])进行获取,通过[[NSObject class] class]这种获取方法是错误的。
代码语言:javascript代码运行次数:0运行复制Class objectClass = [NSObject class];
Class objectWrongMetaClass = [[NSObject class] class];
Class objectMetaClass = object_getClass([NSObject class]);
NSLog(@"%p", objectClass);
NSLog(@"%p", objectWrongMetaClass);
NSLog(@"%p", objectMetaClass);代码语言:javascript代码运行次数:0运行复制0x7fff8a20f140
0x7fff8a20f140
0x7fff8a20f0f0OC 的类信息存放在哪里?成员变量具体的值,放在instance(实例对象)里。属性信息、对象方法信息、协议信息、成员变量信息,放在Class(类对象)里。类方法信息,放在meta-class(元类对象)里。对象的 isa 指针指向哪里?根据上面可知,对象方法存储在class的内存里,类方法存在于meta-class内存里。问题来了,假如现在有一个Person类的实例化对象p1,如果想用p1调用Person类的对象方法personMethod该如何调用呢?毕竟,p1是存储在实例化对象instance内存中的,而personMethod方法是存储于Person类的内存中的。
实际上instance实例的对象的isa指针指向class,找到class类以后,再在class类中找存储于其中的对象方法方法进行调用。
调用类方法的过程也是如此,class类通过其内部的isa指针找到meta-class类中存储的类方法,然后再进行调用。
至此,就可以回答上面的问题了。
instance对象的isa指向class。 当调用对象方法时,通过instance的isa找到class,再找到对象方法进行调用。 class对象的isa指向meta-class。 当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用。 meta-class对象的isa指向基类的meta-class对象。class 对象的 superclass 指针有如下两个类,继承关系如下 :
Student->Person->NSobject
代码语言:javascript代码运行次数:0运行复制@interface Person : NSObject
- (void)personMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personMethod {};
+ (void)personClassMethod {};
@end代码语言:javascript代码运行次数:0运行复制@interface Student : Person
- (void)studentMethod;
+ (void)studentClassMethod;
@end
@implementation Student
- (void)studentMethod {};
+ (void)studentClassMethod {};
@end创建一个实例student
代码语言:javascript代码运行次数:0运行复制Student *student = [[Student alloc] init];调用[student studentMethod]方法的过程- (void)studentMethod;方法存在于Student的class内部。
通过student(实例对象)的isa指针找到Student的class。在Student的class内部找到- (void)studentMethod;方法并调用。调用[student personMethod]方法的过程- (void)personMethod;方法存在于Person的class内部。
通过student(实例对象)的isa指针找到Student的class。在Student的class内部找是否存在- (void)personMethod;方法。不存在,则通过Student的class内的superclass找到Person的class。在Person的class内找是否存在- (void)personMethod;方法。存在->调用方法。调用[student init]方法的过程- (void)init;方法存在于NSObject的class内部。
通过student(实例对象)的isa指针找到Student的class。在Student的class内部找是否存在- (void)init;方法。不存在,则通过Student的class内的superclass指针找到Person的class。在Person的class内找是否存在- (void)init;方法。不存在,则通过Person的class内的superclass指针找到NSObject的meta-class。在NSObject的class内找是否存在- (void)init;方法;存在->调用方法。meta-class 对象的 superclass 指针有如下两个类,继承关系如下 :
Student->Person->NSobject
代码语言:javascript代码运行次数:0运行复制@interface Person : NSObject
- (void)personMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personMethod {};
+ (void)personClassMethod {};
@end代码语言:javascript代码运行次数:0运行复制@interface Student : Person
- (void)studentMethod;
+ (void)studentClassMethod;
@end
@implementation Student
- (void)studentMethod {};
+ (void)studentClassMethod {};
@end调用[Student studentClassMethod];方法的过程+ (void)studentClassMethod;方法存储在Student的meta-class内。
通过Student类对象的isa找到Student的meta-class。在Student的meta-class内找类方法+ (void)studentClassMethod;并调用。调用[Student personClassMethod];方法的过程+ (void)personClassMethod;方法存储在Person的meta-class内
通过Student类对象的isa找到Student的meta-class。 Student的meta-class中不存在+ (void)personClassMethod;方法。通过Student的meta-class内的superclass找到Person的meta-class。在Person的meta-class方法内找是否存在+ (void)personClassMethod;方法。找到方法->调用。调用[Student load];方法的过程+ (void)load;是NSObject的类方法。
通过Student类对象的isa找到Student的meta-class。 Student的meta-class中不存在+ (void)load;方法。通过Student的meta-class内的superclass找到Person的meta-class。在Person的meta-class方法内找是否存在+ (void)load;方法。 Person的meta-class内不存在+ (void)load;方法。通过Person的meta-class内的superclass找到NSObject的meta-class。在NSObject的meta-class内找是否存在+ (void)load;方法。找到方法->调用。isa、superclass 总结下面是一张广为流传关于isa、superclass的经典图。
isa instance的isa指向class class的isa指向meta-class meta-class的isa指向基类的meta-classsuperclass class的superclass指向父类的class 如果没有父类,superclass指针为nil meta-class的superclass指向父类的meta-class 基类的meta-class的superclass指向基类的classinstance 调用对象方法的轨迹isa找到class,方法不存在,就通过superclass找父类。
class 调用类方法的轨迹isa找meta-class方法不存在,就通过superclass找父类。