OC:对象、类、元类

本文探讨了Objective-C中对象、类和元类的概念,解释了为何存在类和元类,并展示了如何通过objc_object结构体理解NSObject、Class和MetaClass之间的关系。通过断点调试和查看class_ro_t结构体,揭示了对象和类的区别,并介绍了如何利用class_getMetaClass方法绘制类与元类的关系图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

老实讲,从Java转OC后头一回碰到元类的概念时有点懵,这篇博文算是往回看,看看oc的对象、类、元类间

参考资料

如果你是头一回知道这个概念,可以先看看别人的文章,和别人的文章

别人的文章里有一副概念图!!

没有为什么(为什么有类和元类?)

看下结论,NSObject,Class,MetaClass都是objc_object结构体。

class和metaclass是objc_object很好证明,代码里写着class的isa是class(具体见class_getMetaClass实现),class是objc_class而objc_class集成objc_object,那么为什么NSObject是objc_object,目前我只能的从objc_isClass(id obj)接受参数id指针(代码里定义为objc_object指针),但可以调用objc_isClass(objcInstance)(传入对象实例)来略窥一二,NSObject也是objc_object。这里对于NSObject是objc_object有直接证明的望指教!

NSObject唯一的私有变量isa指向了Class, Class的isa指向了另一个Class也就是元类。

那么obj和class的区别会在哪里?

    __unused BOOL objIsNotClass = object_isClass(self);
    __unused BOOL ClassIsCls = object_isClass([self class]);
    __unused BOOL MetaClassIsCls = object_isClass(objc_getMetaClass(object_getClassName([self class])));

引入<objc.runtime.h>后可自行测试,self为对象实例


答案很清晰,那么结论那里来?

进入该方法看到最后一步是判断isMetaClass,断点调试,以下是我的实验结果(稍等,哪里有代码?可参考这篇文章末尾

看isMetaClass实现:

bool isMetaClass() {
        assert(this);
        assert(isRealized());
        return data()->ro->flags & RO_META;
    }
这里的ro就是class_ro_t结构体,看下这个结构体

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;
    }
};

断点调试-》打印出class_ro_t结构体:(截的图审核完不见了,这里就贴一下数据好了)

obj的class_ro_t结构体打印数据:

  flags = 128
  instanceStart = 8
  instanceSize = 8
  reserved = 0
  ivarLayout = 0x0000000000000000 <no value available>
  name = 0x0000000100001f4c "OCForwardMsgTest"
  baseMethodList = 0x0000000100002490
  baseProtocols = 0x0000000000000000
  ivars = 0x0000000000000000
  weakIvarLayout = 0x0000000000000000 <no value available>
  baseProperties = 0x0000000000000000

obj的class的class_ro_t结构体其打印数据:

  flags = 129
  instanceStart = 40
  instanceSize = 40
  reserved = 0
  ivarLayout = 0x0000000000000000 <no value available>
  name = 0x0000000100001f4c "OCForwardMsgTest"
  baseMethodList = 0x00000001000023e0
  baseProtocols = 0x0000000000000000
  ivars = 0x0000000000000000
  weakIvarLayout = 0x0000000000000000 <no value available>
  baseProperties = 0x0000000000000000

obj的metaclass的class_ro_t结构体打印数据:

flags = 3
  instanceStart = 40
  instanceSize = 40
  reserved = 0
  ivarLayout = 0x0000000000000000 <no value available>
  name = 0x00000001000f39f5 "NSObject"
  baseMethodList = 0x00000001004a2110
  baseProtocols = 0x00000001004a2870
  ivars = 0x0000000000000000
  weakIvarLayout = 0x0000000000000000 <no value available>
  baseProperties = 0x0000000000000000



简单拿结果套下公式可以知道结果,至于为什么flag会有这样的区别,挖个坑以后再看

画图

利用class_getMetaClass(cls)可以得到

class->metaclass->nsobjectMetaClass->nsobjectMetaClass 这样的路径

再结合superclass就能画出文章开头里别人的文章里的介绍图了

另:

欢迎指出问题和话题讨论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值