Object-C中类与对象的本质

作者: zwwuchn | 来源:发表于2019-08-01 15:06 被阅读14次

通过几道面试题我们来逐渐解开类与对象的本质。

 1. 一个NSObject对象占用多少内存?
 2. 对象isa指针指向哪里?
 3. 什么是class、metaClass对象?
 4. OC的类信息存放在哪里?

Object-C的本质

我们平时编写的Objective-C(后面简称OC)代码,其实底层都是C/C++代码

图片.png

我们来将OC代码转换为C/C++代码

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc 文件名 -o 输出的CPP文件
例如:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp

@interface LPPerson : NSObject
{
    @public
    int _age;
    NSString *_name;
}
@end

@implementation LPPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LPPerson *person = [[LPPerson alloc] init];
        person->_age = 18;
        person->_name = @"LP";
    }
    return 0;
}

我们来看一下源码

struct NSObject_IMPL {
    Class isa; 
};

struct LPPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS; 
    int _age;
    NSString *_name;
};
...
...
图片.png
其实Class在runtime源码中定义 typedef struct objc_class *Class; 稍后我们会分析源码
所以,OC的对象、类都是基于C/C++当中结构体实现的
 1. 一个NSObject对象占用多少内存?
  答:可以看到NSObject_IMPL内部的isa是指向struct objc_class,说明isa是一个指针,在64位系统中
  该对象占用8个字节,但是实际分配了16个字节。我们需要用到下面两个函数

创建一个实例对象,至少需要多少内存?

#import <objc/runtime.h>
class_getInstanceSize([NSObject class]);

创建一个实例对象,实际上分配了多少内存?

#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj);

打印如下:

NSObject *obj = [[NSObject alloc] init];
NSLog(@"%zd",class_getInstanceSize([NSObject class]));
NSLog(@"%zd",malloc_size((__bridge void *const)obj));

OCDemo[25726:949760] 8
OCDemo[25726:949760] 16

实例对象、类、元类(instance、class、meta-class)

Objective-C的runtime是开源的,苹果开源官网下载:objc4
实例对象:一个类的具体实例。
实例对象的结构体数据结构如下:
struct objc_object {
private:
    isa_t isa;
public:
    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();
    ...(省略)
}
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];

object1、object2是NSObject的instance对象(实例对象)它们是不同的两个对象,分别占据着两块不同的内存
  • 通过查看对象的底层代码,同样可以发现,对象在内存中的存储信息包含

    • isa指针
    • 其它成员变量的值等

类:类是定义同一类所有对象的变量和方法的蓝图或原型(维基百科)

类的结构体数据结构如下:

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() { 
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
    ...(省略)
}
struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;

    method_array_t methods; // 类对象方法信息
    property_array_t properties;    // 属性信息
    protocol_array_t protocols;     // 协议信息
    ...(省略)
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;  // 对象占用的内存大小
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
   
    const char * name;  // 类名
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;  // 成员变量列表

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};
图片.png

元类:元类其实就是描述类对象的类

NSObject *obj3 =[[NSObject alloc]init];
Class objMetaClass1 = objc_getMetaClass("NSObject");
Class objMetaClass2 = object_getClass([NSObject class]);
Class objMetaClass3 = object_getClass(object_getClass(obj3));
NSLog(@"%p %p %p",objMetaClass1,objMetaClass2,objMetaClass3);

OCDemo[2418:112622] 0x7fff97fdb0f0 0x7fff97fdb0f0 0x7fff97fdb0f0
objMetaClass1、objMetaClass2、objMetaClass3就是NSObject的meta-class对象(元类对象)
图片.png
BOOL isMetaClass = class_isMetaClass([NSObject class]); // 是否是元类

方法的调用流程

通过以上信息我们就了解到了类、对象、元类之间的关系,那么类方法和对象方法的调用过程是怎样的呢??如下图所示:
图片.png
  • isa指向

    • instance的isa指向class

      • 当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用
    • class的isa指向meta-class

      • 当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用
图片.png
  • class对象的superclass指针

    • 当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用
图片.png
  • meta-class对象的superclass指针

    • 当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用

isa、superclass总结

图片.png
图片.png
开头的面试题应该心中都有答案了吧~

相关文章

  • Object-C对象本质

    Object-C对象本质 OC中对象类型 instance 实例对象isa指针其他成员变量 class 类对象is...

  • Object-C中类与对象的本质

    通过几道面试题我们来逐渐解开类与对象的本质。 Object-C的本质 我们平时编写的Objective-C(后面简...

  • RunTime源码阅读(九)之isa指针,类,元类

    在Object-c中,实例对象的isa指向类对象,类对象的isa指向元类对象。也就是说调用实例对象的方法会查找类中...

  • OC底层原理一对象、alloc分析、isa理解

    一、object-c对象分为实例(Instance)对象、类(Class)对象和元类(Meta-class)对象 ...

  • ios开发进阶-对象模型(1)

    isa 指针 在object-c 中每个对象都有一个isa指针指向它的类。 类中包含信息如下: 1.类的描述信息 ...

  • OC_底层_isa探究

    isa与类关联的原理 OC对象的本质 先简单简介llbd相关知识: 在代码中探索对象本质: 在 main.cpp ...

  • Object-C学习索引

    本系列需要有一定代码基础,总结要点,快速掌握 一、Object-C 对象、消息和类的定义二、Object-C 对象...

  • OC中类的本质

    OC中的对象的本质 对象本身是一个含有isa指针的结构体,isa指针指向对象所属的类类的本质:类本质也是一个结构体...

  • 类的本质

    类的本质 1.类的本质 类的本质其实也是一个对象(类对象) 程序中第一次使用该类的时候被创建,在整个程序中只有一份...

  • 12-类的本质、类的启动过程(load, initialize)

    类的本质 本质类其实也是一个 对象, 这个对象会在这个类第一次被使用的时候创建, 一个类再内存中只有一份类对象只要...

网友评论

    本文标题:Object-C中类与对象的本质

    本文链接:https://www.haomeiwen.com/subject/tjnqdctx.html