OC对象的本质及分类
Object-C的底层都是通过C/C++来实现的,所以OC中的对象也会转化成C/C++中的某一个数据结构,

我们在终端里通过指令
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main_arm64.cpp
将oc代码转化为c++代码,我们可以看到NSObject的底层结构是:
struct NSObject_IMPL {
Class isa;
};
Class是一个指向对象的结构体指针
typedef struct objc_class *Class;
所以NSObject最终会转化成一个结构体,内部只有一个指向对象的结构体指针
所以NSObject对象只会使用8个字节的内存空间来存储指针(当然 实际上给它分配了16个内存空间)
NSLog(@"%zd",class_getInstanceSize([NSObject class])); //实例对象的成员所占用的大小8 (实际使用的) NSLog(@"%zd",malloc_size((__bridge const void *)(obj))); //整个结构体占用的是16(实际分配的)
同时,通过阅读源码我们得知,当创建的对象分配的内存空间小于16个字节的时候 系统都会分配16个字节的空间 这属于是苹果规定。
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < ) size = ;
return size;
}
如果有一个student类继承了object并且有俩个int属性,那么student所占用的内存是多少呢?

student实际占用内存为16字节,系统分配的内存也是16字节。
假设有个person继承NSObject,student继承person,那么person和student各占用多少内存呢?

最终通过打印我们发现,person,实际占用16,系统分配16,student实际占用16,系统分配16.
为什么?person实际占用16??int 4个字节 isa 8个字节 应该是12个字节啊?这就涉及到了前面写到的结构体内存对齐了。
对象的分类
oc中的对象主要可以分为三类:

1.实例对象,就是通过类alloc出来的对象,每次调用alloc都会生成一个新的实例对象

object1 和 object2 就是两个实例对象
实例对象在内存中存储的信息包括:
1、isa指针 (其实isa也算是对象的成员变量 也就是说实例对象内部只包含自己的成员变量)
2、其他成员变量(这里是存储成员变量的具体值)

2、类对象(class)

objectClass1-5 都是NSObject的类对象 ,因为每个类在内存中有且只有一个类对象 所以上面五个类对象其实是同一个对象
类对象在内存中存储的信息主要有:
1、isa指针
2、superclass指针
3、成员变量(这里的成员变量只是描述性的 比如有哪些变量 是什么类型的 并不是实例对象的具体变量值)
4、类的对象方法(-号开头的方法)
5、类的协议信息和属性信息

类对象的本质结构↓↓↓

3、元类对象(meta-class)

objectMetaClass就是NSObject的元类对象,元类对象也是每个类在内存中有且只有一个,元类对象和类对象在结构上非常相似。
元类对象在内存中春初的主要信息有:
1、isa指针
2、superclass指针
3、类方法(+号开头的方法)

我们看到通过object_getclass方法即能获得元类对象 也能获得类对象 通过查看源码我们可以得知object_getclass会判断传进来的参数是类对象还是实例对象 如果是实例对象则返回类对象 如果传进来的是类对象则返回元类对象
我们也可以通过下面的函数来判断对象是不是元类对象

也就是说通过alloc创建的是实例对象 通过object_getclass(类对象)创建的是元类对象 其他对象则是类对象 但是类对象和元类对象有且只有一个
三类对象中 都含有isa指针,那么这个isa指针指向什么?
实例对象的isa指向类对象 类对象的isa指向元类对象 元类对象的isa指向基类的元类对象
正是通过isa指针 才让三种对象产生关联
比如说,一个实例对象想调用对象方法 但是对象方法存放在类对象中 那么就是通过isa找到对象方法再进行调用
同理 当调用类方法的时候 类方法是存放在元类对象中的 类对象通过isa指针找到元类对象 读取类方法列表中的类方法进行调用

superclass指针
在类对象和元类对象中都有一个superclass指针,其实这两种对象中的superclass指针作用类似,都是指向父类对象
类对象中的superclass指针:
比如现在有一个Person对象继承自NSObject 有一个Student继承自Person 当studen的实例对象调用对象方法的时候,首先实例对象会根据自己的isa指针去类对象中找有没有对应的方法 没有的话类对象会根据自己的superclass指针去父类的类对象中去查找(也就是student的类对象根据superclass指针去Person的类对象中去查找有没有对应的对象方法 再没有的话Person的类对象会根据自己的superclass指针去NSObject的类对象中去寻找 寻找到基类在没有对应方法的话就会报方法找不到的错误)

而元类对象中的superclass指针也是指引类对象去父类对象中寻找对应的类方法:
按照上面的例子,Student这个类 想调用一个类方法,首先是Student的类对象 根据isa指针去Student的元类对象中查找有没有对应的类方法 没有的话Student的元类对象会根据自己的superclass指针去父类的元类对象(也就是Person的元类对象)中查找有没有对应的类方法,在没有的话Person的元类对象再根据自己的superclass指针去NSObject的元类对象中寻找 有的话进行调用 没有的话NSObject的元类对象会根据superclass指针去NSObject的类对象中去寻找是否有相同名称的对象方法(这个地方下面会具体讲到为什么基类的superclass指针会指向对应的类对象)


关于上面提到的为什么基类的superclass指针为什么在找不到方法的时候会指向基类的类对象 也就是为什么没有找到对应的类方法的情况下却可以调用同名对象方法?
关于这一点我们通过代码来验证:
首先我们新建一个NSObject的分类,在.h文件中声明一个test的类方法,但在.m文件中并未实现这个类方法 而是实现了同名的对象方法()
#import "NSObject+Test.h" @implementation NSObject (Test) //+ (void)test
//{
// NSLog(@"+[NSObject test] - %p", self);
//} - (void)test
{
NSLog(@"-[NSObject test] - %p", self);
} @end
我们调用类方法发现,及时没有对应的类方法,程序也可以正常运行,并且成功调用了同名的对象方法:

假如我们在m文件没有实现同名test的对象方法,那么程序会报错的:
+[NSObject test]: unrecognized selector sent to class 0x7fffaddd7140
关于在h文件中有类方法的声明,这个是没有影响的 因为没有这个声明的话程序根本跑不起来 我们关注的点是基类的superclass指针为什么在找不到方法的时候会指向基类的类对象寻找同名的对象方法
比如我们在h文件中声明了test的对象方法 m文件没有实现test方法 同样会报unrecognized错 这就是因为基类的对象方法中找不到方法后直接返回空值 而不是像类方法一样从元类对象找不到再去到类对象找同名对象方法
关于基类的superclass指针为什么在找不到方法的时候会指向基类的类对象,这是因为oc在调用方法的时候实际上是转换为c/c++去底层实现的 但是c/c++的底层实现并没有区分类方法还是对象方法 也就是没有区分+-号
比如
[NSObject test];
实际上是转换为了
objc_msgSend([NSObject class], @selector(test))
没有区分+-号 所以在基类元类对象没有找到对应的类方法后回去基类的类对象中查看是否有同名的对象方法 有的话就调用 再没有的话就报错了
NSObject本质揭秘
查看OC对象占用字节数
OC对象的本质及分类的更多相关文章
- iOS进阶一OC对象的本质
OC对象的本质 平时编写的Object-C代码,底层实现其实都是C/C++代码. 所以Objective-C的面向对象都是基于C/C++的数据结构实现的,OC对象内部可以容纳不同数据类型的数据,因此可 ...
- OC 类的本质和分类
一.分类 (一)分类的基本知识 概念:Category 分类是OC特有的语言,依赖于类. 分类的作用:在不改变原来的类内容的基础上,为类增加一些方法. 添加一个分类: 文件结构图: 在分类中添加一 ...
- OC类的本质及分类
(一)类的本质 类对象(class object)与实例对象(instance object) 类本身也是一个对象,是class类型的对象,简称“类对象”. 在/usr/include/objc/ob ...
- OC对象给分类加入属性
OC对象中不能给分类加入属性.可是在实际开发中.常常为了更好的性能须要给分类加入属性,那么 加入的属性不能有默认的成员变量.须要我们自己实现set和get方法,要用到执行时 例如以下: #import ...
- 【OC底层】OC对象本质,如 isa, super-class
Objective-C的本质 1.我们编写的Objective-C,底层现实都是C/C++,代码生成步骤如下: 2.在OC中的所有面向对象的实现,都是基于C/C++的数据结构实现的 3.将Obje ...
- OC基础:OC 基本数据类型与对象之间的转换方法 分类: ios学习 OC 2015-06-18 20:01 11人阅读 评论(0) 收藏
1.Foundation框架中提供了很多的集合类如:NSArray,NSMutableArray,NSSet,NSMutableSet,NSDictionary,NSMutableDictionary ...
- ARC下OC对象和CF对象之间的桥接(bridge)
在开发iOS应用程序时我们有时会用到Core Foundation对象简称CF,例如Core Graphics.Core Text,并且我们可能需要将CF对象和OC对象进行互相转化,我们知道,ARC环 ...
- IOS基础之 (四) OC对象
一 建立一个OC的类 完整的写一个函数:需要函数的声明和定义. 完整的写一个类:需要类的声明和实现. 1.类的声明 声明对象的属性和行为 #import <Foundation/Foundati ...
- OC 对象和匿名对象
OC 对象和匿名对象 对象和匿名对象的定义: 当new出一个对象时,如果用一个指针接收这个对象,那么这个指针通常被称为对象. 如果new出的对象,不用指针接收,那么这个对象就称为匿名对象. #impo ...
随机推荐
- MySQL的分组和排序
分组操作 select count(id) from userinfo group by pat(id); -- 聚合函数: --count --max --sum --avg ---如果对于二次函数 ...
- 腾讯云&搭建微信小程序服务
准备域名和证书 任务时间:20min ~ 40min 小程序后台服务需要通过 HTTPS 访问,在实验开始之前,我们要准备域名和 SSL 证书. 域名注册 如果您还没有域名,可以在腾讯云上选购,过程可 ...
- List多字段排序,orderBy,ThenBy
List排序问题,orderBy,ThenBy 1.List中一个字段排序 前几天做的项目中,获取的List<T>需要用某个字段来进行排序,困扰了很久.用OrderBy解决了.具体是这样的 ...
- Vue 中Bus使用
使用:兄弟组件之间传值: 安装: npm install vue-bus 在main.js 中引入vuebus: import Vue from 'vue'; import VueBus from ' ...
- 分布式服务框架Dubbo入门案例和项目源码
本项目源代码:http://download.csdn.net/detail/fansunion/9498406 Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案, 是 ...
- Maven学习总结(9)——使用Nexus搭建Maven私服
1 . 私服简介 私服是架设在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件.有了私服之后,当 Maven 需要下载构件时,直接请求私服,私服上存在则下载到本地仓库:否则,私服请求外部 ...
- vs2005添加include lib文件目录
vs2005添加include lib文件目录 http://blog.sina.com.cn/s/blog_79489160010145wb.html 1. 添加编译所需要的 lib 文件 [解决方 ...
- 洛谷 P1120 小木棍 [数据加强版]
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...
- [转]十五天精通WCF——第八天 对“绑定”的最后一点理解
转眼已经中断10几天没有写博客了,也不是工作太忙,正好碰到了端午节,然后最近看天津台的爱情保卫战入迷了...太好看了,一直都是回味无穷...而且 涂磊老师话说的真是tmd的经典,然后就这样耽搁了,好了 ...
- HDU 3001
题目中说明每个城市至少要走一次,至多走2次,因此要用到三进制压缩,然后就是状态转移方程了. 这道题就处理三进制的地方麻烦一点.同时注意,在选择最小长度时,一定是要每一个点都经过至少一次的,即是状态的每 ...