iOS OC对象的本质窥探(对象分类)(二)

上面一篇文章讲了OC对象的本质,编译成C++对象是以什么形式存储的,一个对象占多少内存空间等问题,那么在OC语言里面,又分为几种对象呢?其实平时的工作中通过[[NSObject alloc] init]这种形式创建的对象都是实例对象,另外还有两类平时接触甚少的对象,一个是类对象,一个就是元类对象。

开篇引题 类对象分为三种:
实例对象
类对象
元类对象
这三中类型的对象之间是什么关系?每种类型的对象又有什么特点呢?

开始一探究竟
  • 实例对象
    实现以下代码
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];        
NSLog(@"%p %p",
              object1,
              object2);

打印:0x100648340 0x100647440

总结:不多讲了,第一篇文章已经写的很详细,
object1、object2是NSObject的instance对象(实例对象)
它们是不同的两个对象,分别占据着两块不同的内存
instance对象在内存中存储的信息包括
isa指针
其他成员变量

存储的是各个成员变量的值,还有一个isa指针,一个类在内存中的实例对象可以有多个。

内存存储图示


实例对象内存存储图示.png
  • 类对象
    1.获取类对象
    两种方法
NSObject *object1 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];

还可以通过一个runtime函数

NSObject *object1 = [[NSObject alloc] init];        
Class objectClass3 = object_getClass(object1);

object_getClass 函数:传入实例对象返回类对象,传入类对象,返回元类对象
下面实现以下代码

NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
        
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];
        
NSLog(@"%p %p",
              object1,
              object2);
        
NSLog(@"%p %p %p %p %p",
              objectClass1,
              objectClass2,
              objectClass3,
              objectClass4,
              objectClass5);

打印:0x100648340 0x100647440
     0x7fff9dab4118 0x7fff9dab4118 0x7fff9dab4118 0x7fff9dab4118 0x7fff9dab4118

会发现两个实例对象的内存地址是不一样的,而通过两个实例对象获得的5个类对象的指针都是一样的,说明,一个类在内存中只有一个类对象。

总结:
objectClass1 ~ objectClass5都是NSObject的class对象(类对象)
它们是同一个对象。每个类在内存中有且只有一个class对象
class对象在内存中存储的信息主要包括
isa指针
superclass指针
类的属性信息(@property)、类的对象方法信息(instance method)
类的协议信息(protocol)、类的成员变量信息(ivar)
......

内存存储图示


类对象内存存储图示.png
  • 元类对象
    执行以下代码获取元类对象
// object_getClass  函数:传入实例对象返回类对象,传入类对象,返回元类对象
Class objectClass3 = object_getClass([NSObject class]);

总结:
objectMetaClass是NSObject的meta-class对象(元类对象)
每个类在内存中有且只有一个meta-class对象
meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息主要包括
isa指针
superclass指针
类的类方法信息(class method)
......

元类对象内存图示.png

关于如何证明刚刚所总结的三种类型的对象分别存储的什么信息,通过阅读苹果源码可知

分析:实例对象,类对象和元类对象中都有isa指针,而类对象和元类对象中除了含有isa指针之外还有superclass指针,问题:isa指针和superclass指针分别有什么作用呢?

  • 分析 创建一个Person类给person类分别声明一个对象方法和一个类方法
// Person
@interface Person : NSObject <NSCopying>
{
    @public
    int _age;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end

@implementation Person
- (void)personInstanceMethod{
}
+ (void)personClassMethod{
}
@end

// 调用 
Person *person = [[Person alloc] init];
[person personInstanceMethod];
[Person personClassMethod];
  • isa指针作用
    OC语言是消息机制 当执行[person personInstanceMethod]; 这行代码时 实际会被编译成 objc_msgSend(person, @selector(personInstanceMethod))进行调用,那么刚刚说到实例对象中不存储方法,那么当调用时这个对象方法是怎么获得的呢?
    答案: 当实例对象调用对象方法时是通过isa指针,指向自己的类对象,找到类对象中的方法信息,进行调用。同理,当执行 [Person personClassMethod]; 这行代码时,实例对象通过isa指针指向自己的类对象,又通过类对象中的isa指针指向元类对象,获取到类方法信息。
    图示:

    isa指针作用.png

  • 创建一个Person类给person类分别声明一个对象方法和一个类方法,再创建一个继承于Person类的Student类给Student类分别声明一个对象方法和一个类方法

// Person
@interface Person : NSObject <NSCopying>
{
    @public
    int _age;
}
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end

@implementation Person

- (void)personInstanceMethod
{
    
}
+ (void)personClassMethod
{
    
}
@end

// Student
@interface Student : Person <NSCoding>
{
@public
    int _weight;
}
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end

@implementation MJStudent
- (void)studentInstanceMethod
{
    
}
+ (void)studentClassMethod
{
    
}
@end

// 调用
Student *student = [[Student alloc] init];
[student personInstanceMethod];
[Student personClassMethod];     
  • superclass指针作用
    总结:当执行[student personInstanceMethod]这行代码时 student对象通过isa指针找到自己类对象,结果发现类对象中没有personInstanceMethod这个方法,然后利用superclass指针找到父类也就是Person的类对象,查看是否有 personInstanceMethod 方法信息,如果有 就调用,没有的话继续向上查找。同理:当执行[Student personClassMethod]; 这行代码时,student对象通过isa指针找到自己类对象,又通过类对象的isa指针找到自己的元类对象结果发现元类对象中没有personClassMethod这个方法,元类对象利用superclass指针向上逐级寻找父类的元类对象是否有此方法。直到NSobject停止,如果找到就调用,找不到就会奔溃 unrecognized selector sent to class 0x1000011a0'

图示:


superclass指针作用.png

最后总结:

instance -> 实例对象,class -> 类对象,meta-class -> 元类对象

1.instance的isa指向class
2.class的isa指向meta-class
3.meta-class的isa指向基类的meta-class
4.class的superclass指向父类的class
5.如果没有父类,superclass指针为nil
6.meta-class的superclass指向父类的meta-class
7.基类的meta-class的superclass指向基类的class
8.instance调用对象方法的轨迹
9.isa找到class,方法不存在,就通过superclass找父类
10.class调用类方法的轨迹
11.isa找meta-class,方法不存在,就通过superclass找父类

图示:


WeChataf27bd994cb5722150a32f853afae3b5.png
  • 画一下[student personInstanceMethod]这行代码的执行顺序


    [student personInstanceMethod]执行顺序.png
  • 画一下[Student load]这行代码的执行顺序


    [Student load]执行顺序.png

疑问???类方法再调用时先去自己的元类对象中寻找,如果没有就去父类的元类对象中寻找,在没有就去NSObject的元类对象中寻找,再就去NSObject的类对象中寻找(根据最上面的线可以看来)那是这么回事吗?下面来验证一下

//新建一个Car类,继承自NSObject
@interface Car : NSObject

@end

@implementation Car

@end

// 创建一个NSObject的类别
//.h中代码
+ (void)test;
//.m中代码
+ (void)test{
    NSLog(@"+[NSObject test] - %p", self);
}
//调用代码
[Car test];

输出 :[Car class] - 0x100001220

别的代码都不变,将类别中.m中的代码改成

//+号变成-号
- (void)test{
    NSLog(@"+[NSObject test] - %p", self);
}

输出 :[Car class] - 0x100001220

再调用发现还是可以成功,具体的原因吧,我也说的不是很好,就不误导别人了,如果有大神知晓,欢迎指正

如有疑问欢迎指正~

强烈推荐:
iOS OC对象的本质窥探(一)
iOS获取手机唯一标示
iOS 高德地图实现大头针展示,分级大头针,自定制大头针,在地图上画线,线和点共存,路线规划(驾车路线规划),路线导航,等一些常见的使用场景

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345