YYDS

OC 对象的分类

2018-03-20  本文已影响132人  一位不愿透露姓名的王先生_

Objective-C中的对象,简称OC对象,主要可以分为3

instance

instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象

NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];

NSLog(@"%p", obj1);
NSLog(@"%p", obj2);

打印结果会输出

0x1004992a0
0x1004974f0

由此可以看出,obj1obj2是两个不同的对象,分别占据着两块不同的内存。

instance对象在内存中存储的信息包括

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

经过调试可以发现5Class类指向同一个地址值0x00007fff8a20f140,它和instance对象的区别是instance对象是alloc分配的内存空间,每个实例对象都占用不同的空间,但是Class一个类只占用一份内存空间。

meta-class

classmeta-class内存地址值比较

Class objectClass = [NSObject class];
Class objectMetaClass = object_getClass([NSObject class]);

NSLog(@"%p", objectClass);
NSLog(@"%p", objectMetaClass);
0x7fff8a20f140
0x7fff8a20f0f0

对比发现,Classmeta-class的内存地址不一样。我们可以进行如下总结 :

注意

获取元类的内存地址只能通过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 的类信息存放在哪里?

对象的 isa 指针指向哪里?

根据上面可知,对象方法存储在class的内存里,类方法存在于meta-class内存里。问题来了,假如现在有一个Person类的实例化对象p1,如果想用p1调用Person类的对象方法personMethod该如何调用呢?毕竟,p1是存储在实例化对象instance内存中的,而personMethod方法是存储于Person类的内存中的。

实际上instance实例的对象的isa指针指向class,找到class类以后,再在class类中找存储于其中的对象方法方法进行调用。

调用类方法的过程也是如此,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;方法存在于Studentclass内部。

调用[student personMethod]方法的过程

- (void)personMethod;方法存在于Personclass内部。

调用[student init]方法的过程

- (void)init;方法存在于NSObjectclass内部。

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;方法存储在Studentmeta-class内。

调用[Student personClassMethod];方法的过程

+ (void)personClassMethod;方法存储在Personmeta-class

调用[Student load];方法的过程

+ (void)load;NSObject的类方法。

isa、superclass 总结

下面是一张广为流传关于isasuperclass的经典图。

isa

superclass

instance 调用对象方法的轨迹

isa找到class,方法不存在,就通过superclass找父类。

class 调用类方法的轨迹

isameta-class方法不存在,就通过superclass找父类。

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3tasm3b0bwoww

上一篇下一篇

猜你喜欢

热点阅读