OC 对象的分类
Objective-C
中的对象,简称OC
对象,主要可以分为3
种
-
instance
对象(实例对象) -
class
对象(类对象) -
meta-class
对象(元类对象)
instance
instance
对象就是通过类alloc
出来的对象,每次调用alloc
都会产生新的instance
对象
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
NSLog(@"%p", obj1);
NSLog(@"%p", obj2);
打印结果会输出
0x1004992a0
0x1004974f0
由此可以看出,obj1
和obj2
是两个不同的对象,分别占据着两块不同的内存。
而instance
对象在内存中存储的信息包括
-
isa
指针 - 成员变量的值
_age = 5
,这个5
就是存在于实例对象中的
Class 对象
查看以下代码中的内存地址
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);
在控制台调试打印地址
(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-class
class
和meta-class
内存地址值比较
Class objectClass = [NSObject class];
Class objectMetaClass = object_getClass([NSObject class]);
NSLog(@"%p", objectClass);
NSLog(@"%p", objectMetaClass);
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]
这种获取方法是错误的。
Class objectClass = [NSObject class];
Class objectWrongMetaClass = [[NSObject class] class];
Class objectMetaClass = object_getClass([NSObject class]);
NSLog(@"%p", objectClass);
NSLog(@"%p", objectWrongMetaClass);
NSLog(@"%p", objectMetaClass);
0x7fff8a20f140
0x7fff8a20f140
0x7fff8a20f0f0
OC 的类信息存放在哪里?
- 成员变量具体的值,放在
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
@interface Person : NSObject
- (void)personMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personMethod {};
+ (void)personClassMethod {};
@end
@interface Student : Person
- (void)studentMethod;
+ (void)studentClassMethod;
@end
@implementation Student
- (void)studentMethod {};
+ (void)studentClassMethod {};
@end
创建一个实例student
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
@interface Person : NSObject
- (void)personMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personMethod {};
+ (void)personClassMethod {};
@end
@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-class
superclass
-
class
的superclass
指向父类的class
- 如果没有父类,
superclass
指针为nil
- 如果没有父类,
-
meta-class
的superclass
指向父类的meta-class
- 基类的
meta-class
的superclass
指向基类的class
instance 调用对象方法的轨迹
isa
找到class
,方法不存在,就通过superclass
找父类。
class 调用类方法的轨迹
isa
找meta-class
方法不存在,就通过superclass
找父类。
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3tasm3b0bwoww