我们平时编写的Objective-C代码,底层实现其实都是C\C++代码
将Objective-C代码转换为C\C++代码
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件
如果需要链接其他框架,使用-framework参数。比如-framework UIKit
NSObject的底层实现
所以Objective-C的面向对象都是基于C\C++的 结构体
的数据结构实现的
一个NSObject对象占用多少内存?
方式一:系统函数
- 系统分配了16个字节给NSObject对象(通过
malloc_size
函数获得) - 但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过
class_getInstanceSize
函数获得) ```objectivec NSObject *obj = [[NSObject alloc] init]; // 16个字节
// 获得NSObject实例对象的成员变量所占用的大小 >> 8 NSLog(@”%zd”, class_getInstanceSize([NSObject class]));
// 获得obj指针所指向内存的大小 >> 16 NSLog(@”%zd”, malloc_size((__bridge const void *)obj));
> 可在这里查看源码实现:[https://opensource.apple.com/tarballs/objc4/](https://opensource.apple.com/tarballs/objc4/)
<a name="yq5BN"></a>
##### 容易混淆的函数
创建一个实例对象,至少需要多少内存?
```objectivec
#import <objc/runtime.h>
class_getInstanceSize([NSObject class]);
创建一个实例对象,实际上分配了多少内存?
#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj);
方式二:Xcode 工具
- 实时查看内存数据 Debug -> Debug Workfllow -> View Memory (Ctrl + Option + Shift + Command + M)
方式三:LLDB指令
- print、p:打印
- po:打印对象
读取内存
- memory read/数量格式字节数 内存地址
- x/数量格式字节数 内存地址
x/3xw 0x10010
格式
- x是16进制,
- f是浮点,
- d是10进制
字节大小
- b:byte 1字节,
- h:half word 2字节
- w:word 4字节,
- g:giant word 8字节
修改内存中的值
memory write 内存地址 数值
memory write 0x0000010 10
(lldb) p obj (NSObject *) $1 = 0x000000010810e1d0 (lldb) print obj (NSObject *) $2 = 0x000000010810e1d0 (lldb) po obj <NSObject: 0x10810e1d0> (lldb) memory read 0x10810e1d0 0x10810e1d0: c9 1c 98 88 ff ff 1d 01 00 00 00 00 00 00 00 00 ................ 0x10810e1e0: 2d 5b 4e 53 54 6f 75 63 68 42 61 72 43 6f 6c 6f -[NSTouchBarColo (lldb) x 0x10810e1d0 0x10810e1d0: c9 1c 98 88 ff ff 1d 01 00 00 00 00 00 00 00 00 ................ 0x10810e1e0: 2d 5b 4e 53 54 6f 75 63 68 42 61 72 43 6f 6c 6f -[NSTouchBarColo (lldb) x/3gx 0x10810e1d0 0x10810e1d0: 0x011dffff88981cc9 0x0000000000000000 0x10810e1e0: 0x63756f54534e5b2d (lldb) memory write 0x10810e1d8 3 (lldb) x 0x10810e1d0 0x10810e1d0: c9 1c 98 88 ff ff 1d 01 03 00 00 00 00 00 00 00 ................ 0x10810e1e0: 2d 5b 4e 53 54 6f 75 63 68 42 61 72 43 6f 6c 6f -[NSTouchBarColo
OC对象的分类
instance对象(实例对象)
- class对象(类对象)
-
instance
instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
object1、object2是NSObject的instance对象(实例对象)
- 它们是不同的两个对象,分别占据着两块不同的内存
instance对象在内存中存储的信息包括
- isa指针
- 其他成员变量
class
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1); //Runtime API
Class objectClass4 = object_getClass(object2); //Runtime API
Class objectClass5 = [NSObject class];
NSLog(@"%p %p",
object1,
object2);
NSLog(@"%p %p %p %p %p",
objectClass1,
objectClass2,
objectClass3,
objectClass4,
objectClass5);
objectClass1 ~ objectClass5
都是NSObject的class对象(类对象)- 它们是同一个对象。每个类在内存中有且只有一个class对象
class对象在内存中存储的信息主要包括
- isa指针
- superclass指针
- 类的属性信息(@property)
- 类的对象方法信息(instance method)
- 类的协议信息(protocol)
- 类的成员变量信息(ivar)
- ……
meta-class
// meta-class对象,元类对象
// 将类对象当做参数传入,获得元类对象
Class objectMetaClass = object_getClass(objectClass5); //Runtime API
- objectMetaClass是NSObject的meta-class对象(元类对象)
- 每个类在内存中有且只有一个meta-class对象
- meta-class对象和class对象的内存结构是一样的,但是用途不一样
在内存中存储的信息主要包括
- isa指针
- superclass指针
- 类的类方法信息(class method)
- ……
注意:以下代码获取的objectClass是class对象,并不是meta-class对象
Class objectMetaClass2 = [[NSObject class] class];
查看Class是否为meta-class
#import <objc/runtime.h>
BOOL result = class_isMetaClass([NSObject class]);
objc_getClass、object_getClass、class区别
- Class objc_getClass(const char *aClassName)
- 传入字符串类名
- 返回对应的类对象
- Class object_getClass(id obj)
- 传入的obj可能是instance对象、class对象、meta-class对象
- 返回值
- 如果是instance对象,返回class对象
- 如果是class对象,返回meta-class对象
- 如果是meta-class对象,返回NSObject(基类)的meta-class对象
- (Class)class、+ (Class)class
- 返回的就是类对象
isa、superclass总结
- instance的isa指向class
- class的isa指向meta-class
- meta-class的isa指向基类的meta-class
- class的superclass指向父类的class 如果没有父类,superclass指针为nil
- meta-class的superclass指向父类的meta-class 基类的meta-class的superclass指向基类的class
- instance调用对象方法的轨迹 isa找到class,方法不存在,就通过superclass找父类
- class调用类方法的轨迹 isa找meta-class,方法不存在,就通过superclass找父类
- 从64bit开始,isa需要进行一次位运算,才能计算出真实地址
- class、meta-class对象的本质结构都是struct objc_class
OC的类信息存放在哪里?
- 对象方法、属性、成员变量、协议信息,存放在class对象中
- 类方法,存放在meta-class对象中
- 成员变量的具体值,存放在instance对象