美文网首页
iOS实例、类、元类

iOS实例、类、元类

作者: 康小曹 | 来源:发表于2020-11-03 18:07 被阅读0次

从源码看本质

源代码:

@interface XKPerson ()

@property (copy, nonatomic) NSString *name;

@end

@implementation XKPerson

+ (instancetype)personWithName:(NSString *)name {
    XKPerson *p = [XKPerson new];
    p.name = name;
    return p;
}

转化成cpp,整理相关代码:

// 对象信息的实际存储者
struct _class_ro_t {
    unsigned int flags;
    unsigned int instanceStart;
    unsigned int instanceSize;
    const unsigned char *ivarLayout;
    const char *name;
    const struct _method_list_t *baseMethods;
    const struct _objc_protocol_list *baseProtocols;
    const struct _ivar_list_t *ivars;
    const unsigned char *weakIvarLayout;
    const struct _prop_list_t *properties;
};

// 定义了XKPerson的元类
static struct _class_ro_t _OBJC_METACLASS_RO_$_XKPerson = {
    1, sizeof(struct _class_t), sizeof(struct _class_t), 
    0, 
    "XKPerson",
    (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_XKPerson,
    0, 
    0, 
    0, 
    0, 
};

// 定义了XKPerson的类对象
static struct _class_ro_t _OBJC_CLASS_RO_$_XKPerson = {
    0, __OFFSETOFIVAR__(struct XKPerson, _name), sizeof(struct XKPerson_IMPL), 
    0, 
    "XKPerson",
    (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_XKPerson,
    0, 
    (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_XKPerson,
    0, 
    0, 
};

// 对象的管理者
struct _class_t {
    // 传说中的isa
    struct _class_t *isa;
    // 传说中的superclass
    struct _class_t *superclass;
    // 缓存相关
    void *cache;
    // 暂不使用
    void *vtable;
    // 对象信息的实际保存者
    struct _class_ro_t *ro;
};

struct _class_t OBJC_METACLASS_$_NSObject;

// 是_class_t,用于管理_XKPerson元类
struct _class_t OBJC_METACLASS_$_XKPerson = {
    0, // &OBJC_METACLASS_$_NSObject,
    0, // &OBJC_METACLASS_$_NSObject,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_METACLASS_RO_$_XKPerson,
};

struct _class_t OBJC_CLASS_$_NSObject;

// 是_class_t,管理XKPerson的类对象
struct _class_t OBJC_CLASS_$_XKPerson __attribute__ ((used, section ("__DATA,__objc_data"))) = {
    0, // &OBJC_METACLASS_$_XKPerson,
    0, // &OBJC_CLASS_$_NSObject,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_CLASS_RO_$_XKPerson,
};

// 真正使用的是_class_t,需要对齐进行初始化
static void OBJC_CLASS_SETUP_$_XKPerson(void ) {
  // 所有元类的isa指向根源类,也就是metaNSObject
  // metaNSObject的isa指向跟类对象,也就是classNSObject
    OBJC_METACLASS_$_XKPerson.isa = &OBJC_METACLASS_$_NSObject;
  // 元类的superclass指向父元类
    OBJC_METACLASS_$_XKPerson.superclass = &OBJC_METACLASS_$_NSObject;
    OBJC_METACLASS_$_XKPerson.cache = &_objc_empty_cache;

  // 类对象的isa指向元类
    OBJC_CLASS_$_XKPerson.isa = &OBJC_METACLASS_$_XKPerson;
  // 类对象的superclass指向父[类对象]
  // 跟类对象(classNSObject)指向为nil,触发消息转发机制
    OBJC_CLASS_$_XKPerson.superclass = &OBJC_CLASS_$_NSObject;
    OBJC_CLASS_$_XKPerson.cache = &_objc_empty_cache;
}
实例-类对象-元类

为什么 [[obj class] class] 方法获取不到元类

实例对象、类对象、元类的获取代码如下:

        NSObject *obj1 = [[NSObject alloc] init];
        NSObject *obj2 = [[NSObject alloc] init];
        NSObject *obj3 = [[NSObject alloc] init];
        
        NSLog(@"instance address:%p %p %p",obj1, obj2, obj3);
        NSLog(@"class address: %p %p %p",[obj1 class], [obj2 class], [obj3 class]);
        NSLog(@"meta class address:%p %p %p",object_getClass([obj1 class]), object_getClass([obj2 class]), object_getClass([obj3 class]));
        NSLog(@"error meta class address:%p %p %p",[[obj1 class] class], [[obj2 class] class], [[obj3 class] class]);

打印结果:

2020-11-04 09:05:26.264248+0800 XKObjTest[82779:33963605] instance address:0x10285f9a0 0x10285ffb0 0x10285e3d0
2020-11-04 09:05:26.265428+0800 XKObjTest[82779:33963605] class address: 0x7fff9b7d5140 0x7fff9b7d5140 0x7fff9b7d5140
2020-11-04 09:05:26.265520+0800 XKObjTest[82779:33963605] meta class address:0x7fff9b7d50f0 0x7fff9b7d50f0 0x7fff9b7d50f0
2020-11-04 09:05:26.265600+0800 XKObjTest[82779:33963605] error meta class address:0x7fff9b7d5140 0x7fff9b7d5140 0x7fff9b7d5140
Program ended with exit code: 0

我们都知道[[instance class] class]这样是无法获取到元类的,那原因是什么呢?查找 objc 源码得到 class 方法的源码:

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

如上图所示,虽然 class 方法本质是调用 object_getClass,但是类方法 class 确是直接返回自己,也就是类对象,所以类对象无论调用多少次 class 方法,返回的都是类对象自己。

而 object_getClass 的源码如下:

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

这个方法直接返回的是 isa 指针的指向,所以可以获取到元类;

相关文章

  • iOS实例、类、元类

    从源码看本质 源代码: 转化成cpp,整理相关代码: 为什么 [[obj class] class] 方法获取不到...

  • Python 元类

    什么是元类?元类就是创建类的类,type是最原始的一个元类。(实例是实例化的类,而类是元类的实例)python中一...

  • iOS 的实例对象、类、元类

    级别:★★☆☆☆标签:「实例对象」「类」「元类」「实例对象、类、元类」作者: ITWYW[https://www....

  • iOS类的结构分析

    一、实例对象、类、元类关系分析 1. 实例对象、类、元类关系图解析 我相信上面这张经典的实例对象、类、元类关系图大...

  • 3.isa

    isa指向 ->实例isa -> 类|类isa -> 元类 | 元类isa -> 根元类|根元类isa -> 根元...

  • iOS内存分配

    iOS对象有3种: 实例对象 类对象 元类对象 对象(对象都是结构体)的内存中,包含的指针: isa 实例对象is...

  • 类的结构分析

    对象、类、元类、根元类 对象是类的实例,对象是以类为模版来创建的。类的实质上也是一个对象,类是元类的实例对象。类对...

  • iOS 对实例、类对象、元类、根元类验证

    精华Pod库分享 tableveiw 刷新控件 VNHttpRequest 一、类、根类、元类、根元类关系图 网上...

  • oc对象实现图解

    ios第一篇(oc对象) ios类对象和元类对象以及对象的关系 类对象中存储的是对象的实例方法,属性,成员变量,协...

  • iOS开发进阶(唐巧)阅读笔记

    一、iOS开发底层原理 1:类也是一个对象,所以它必须是另一个类的实例,这个类就是元类(metaclass)。 我...

网友评论

      本文标题:iOS实例、类、元类

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