我们平时编写的Objective-C代码,底层实现其实都是C\C++代码
image.png
将Objective-C代码转换为C\C++代码

  1. xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件

如果需要链接其他框架,使用-framework参数。比如-framework UIKit

NSObject的底层实现

image.png
image.png
所以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));

  1. > 可在这里查看源码实现:[https://opensource.apple.com/tarballs/objc4/](https://opensource.apple.com/tarballs/objc4/)
  2. <a name="yq5BN"></a>
  3. ##### 容易混淆的函数
  4. 创建一个实例对象,至少需要多少内存?
  5. ```objectivec
  6. #import <objc/runtime.h>
  7. 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)

image.png
image.pngimage.png

方式三: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对象(类对象)
  • meta-class对象(元类对象)

    instance

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

  • object1、object2是NSObject的instance对象(实例对象)

  • 它们是不同的两个对象,分别占据着两块不同的内存

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

  • isa指针
  • 其他成员变量

image.pngimage.png

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)
  • ……

image.png

meta-class

// meta-class对象,元类对象
// 将类对象当做参数传入,获得元类对象
Class objectMetaClass = object_getClass(objectClass5); //Runtime API
  • objectMetaClass是NSObject的meta-class对象(元类对象)
  • 每个类在内存中有且只有一个meta-class对象
  • meta-class对象和class对象的内存结构是一样的,但是用途不一样

在内存中存储的信息主要包括

  • isa指针
  • superclass指针
  • 类的类方法信息(class method)
  • ……

image.png

注意:以下代码获取的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区别

  1. Class objc_getClass(const char *aClassName)
  • 传入字符串类名
  • 返回对应的类对象
  1. 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总结

image.png

  • 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找父类

image.png

  • 从64bit开始,isa需要进行一次位运算,才能计算出真实地址image.png
  • class、meta-class对象的本质结构都是struct objc_class

OC的类信息存放在哪里?

  • 对象方法、属性、成员变量、协议信息,存放在class对象中
  • 类方法,存放在meta-class对象中
  • 成员变量的具体值,存放在instance对象