老实讲,从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就能画出文章开头里别人的文章里的介绍图了
另:
欢迎指出问题和话题讨论