美文网首页
类的结构探一探

类的结构探一探

作者: 灰溜溜的小王子 | 来源:发表于2020-09-17 17:39 被阅读0次

对象、类、元类、根元类的关系

先温习下这个图

先背背图
  • 类的本质

首先准备可调试objc源码,配置可执行的objc源码

#import <Foundation/Foundation.h>
#import "PHPerson.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
       
        PHPerson * phPerson = [PHPerson alloc];
        Class pClass = object_getClass(phPerson);
        
    }
    return 0;
}

cd到main.m所在目录clang命令:
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m

main.m文件输出.cpp如图


PHPerson * phPerson = ((PHPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("PHPerson"), sel_registerName("alloc"));

Class是什么?在objc源码找到
typedef struct objc_class *Class探知Class的类型是objc_class.

那么 objc_class又是什么?
继续跟进:


可知objc_class继承于objc_object
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() const {
        return bits.data();
    }
....//省略
}

总结: 类的本质是objc_class类型的结构体,objc_class继承于objc_object

问题:不是说对象继承与NSObject?跟objc_object有什么关系?

1.同样在objc源码中找到NSObject的定义

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}

NSObject中存在Class类型的成员变量isaClass又是objc_class类型的结构体且objc_class继承于objc_object的结构体;

结论:NSObject类是OC版本objc_object

问题:isa明明是isa_t类型的,为什么注释了一句Class ISA
1.万物皆对象,用继承于objc_objectClass接收是没问题的
2.强转,方便isa走位时返回类的类型

  • 类的结构

objc_class的定义

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() const {
        return bits.data();
    }
....
}

1.Class ISA

  • 不但实例对象中有isa指针,类对象中也有isa指针关联着元类,
    Class本身就是一个指针,占用8字节

2.Class superclass

  • 顾名思义就是类的父类(一般为NSObjectsuperclassClass类型,所以占用8字节

3.cache_t cache
-cache_t是一个结构体,内存长度有所有元素决定:_buckets是一个指针,占用8字节;mask_t是个int类型_mask占用4字节_occupied占用4字节


struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    explicit_atomic<struct bucket_t *> _buckets;//8字节
    explicit_atomic<mask_t> _mask;//4字节
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
    explicit_atomic<uintptr_t> _maskAndBuckets;
#if __LP64__
    uint16_t _flags; //2字节
#endif
    uint16_t _occupied;//2字节
  ...
};

typedef uint32_t mask_t;  // x86_64 & arm64 asm are less efficient with 16-bits

合计:cache_t占用16字节

4.class_data_bits_t bits
根据字母意思就是大小内存猜下也就是存数据

struct class_data_bits_t {
    friend objc_class;

    // Values are the FAST_ flags above.
    uintptr_t bits;
private:
    bool getBit(uintptr_t bit) const
    {
        return bits & bit;
    }

    void setBits(uintptr_t set) {
        __c11_atomic_fetch_or((_Atomic(uintptr_t) *)&bits, set, __ATOMIC_RELAXED);
    }

public:

    class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    void setData(class_rw_t *newData)
    {
        ASSERT(!data()  ||  (newData->flags & (RW_REALIZING | RW_FUTURE)));
        // Set during realization or construction only. No locking needed.
        // Use a store-release fence because there may be concurrent
        // readers of data and data's contents.
        uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
        atomic_thread_fence(memory_order_release);
        bits = newBits;
    }
};

class_data_bits_t 存储的就是类相关的东西

 class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }

点击进入源码


struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint16_t witness;
#if SUPPORT_INDEXED_ISA
    uint16_t index;
#endif

    explicit_atomic<uintptr_t> ro_or_rw_ext;

    Class firstSubclass;
    Class nextSiblingClass;

private:
    using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t *, class_rw_ext_t *>;

    const ro_or_rw_ext_t get_ro_or_rwe() const {
        return ro_or_rw_ext_t{ro_or_rw_ext};
    }

    void set_ro_or_rwe(const class_ro_t *ro) {
        ro_or_rw_ext_t{ro}.storeAt(ro_or_rw_ext, memory_order_relaxed);
    }

    void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
        // the release barrier is so that the class_rw_ext_t::ro initialization
        // is visible to lockless readers
        rwe->ro = ro;
        ro_or_rw_ext_t{rwe}.storeAt(ro_or_rw_ext, memory_order_release);
    }

    class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);

public:
    void setFlags(uint32_t set)
    {
        __c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
    }

    void clearFlags(uint32_t clear) 
    {
        __c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
    }

    // set and clear must not overlap
    void changeFlags(uint32_t set, uint32_t clear) 
    {
        ASSERT((set & clear) == 0);

        uint32_t oldf, newf;
        do {
            oldf = flags;
            newf = (oldf | set) & ~clear;
        } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
    }

    class_rw_ext_t *ext() const {
        return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>();
    }

    class_rw_ext_t *extAllocIfNeeded() {
        auto v = get_ro_or_rwe();
        if (fastpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>();
        } else {
            return extAlloc(v.get<const class_ro_t *>());
        }
    }

    class_rw_ext_t *deepCopy(const class_ro_t *ro) {
        return extAlloc(ro, true);
    }

    const class_ro_t *ro() const {//成员变量(猜的)
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>()->ro;
        }
        return v.get<const class_ro_t *>();
    }

    void set_ro(const class_ro_t *ro) {//类方法列表(猜)
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            v.get<class_rw_ext_t *>()->ro = ro;
        } else {
            set_ro_or_rwe(ro);
        }
    }

    const method_array_t methods() const {//实例方法列表
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
        }
    }

    const property_array_t properties() const {//属性列表
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>()->baseProperties};
        }
    }

    const protocol_array_t protocols() const {//协议列表
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
        }
    }
};

这个信息也很重要 特别是ro()

struct class_rw_ext_t {
    const class_ro_t *ro;
    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;
    char *demangledName;
    uint32_t version;
};
  • 类的相关方法


如图添加成员变量nickName,属性name,类方法+ (void)walk 和实例方法- (void)fly 类结构打印

bits刚好是类的内存首地址+isa、superclass、cache的内存长度==>0x100003250+32字节 =0x100003270

类信息地址打印 类信息地址打印

通过指针地址访问data()获取类信息的数据

获取类信息的数据

访问class_rw_tproperties属性得到对象的属性,可以看出是个数组类型property_array_t

image.png 获取这跟个属性列表,刺死的$5是数组的第一个数据的地址也是数组的首地址,通过下标指向顺序访问列表数据 image.png

变量中为啥只有name没有nickName,猜测这个成员变量nickName还是在这块存着,发现这个玩意儿

const class_ro_t *ro() const {//成员变量(猜的)
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>()->ro;
        }
        return v.get<const class_ro_t *>();
    }

底层:


struct protocol_list_t {
    // count is pointer-sized by accident.
    uintptr_t count;
    protocol_ref_t list[0]; // variable-size

    size_t byteSize() const {
        return sizeof(*this) + count*sizeof(list[0]);
    }

    protocol_list_t *duplicate() const {
        return (protocol_list_t *)memdup(this, this->byteSize());
    }

    typedef protocol_ref_t* iterator;
    typedef const protocol_ref_t* const_iterator;

    const_iterator begin() const {
        return list;
    }
    iterator begin() {
        return list;
    }
    const_iterator end() const {
        return list + count;
    }
    iterator end() {
        return list + count;
    }
};

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;

    // This field exists only when RO_HAS_SWIFT_INITIALIZER is set.
    _objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];

    _objc_swiftMetadataInitializer swiftMetadataInitializer() const {
        if (flags & RO_HAS_SWIFT_INITIALIZER) {
            return _swiftMetadataInitializer_NEVER_USE[0];
        } else {
            return nil;
        }
    }

    method_list_t *baseMethods() const {
        return baseMethodList;
    }

    class_ro_t *duplicate() const {
        if (flags & RO_HAS_SWIFT_INITIALIZER) {
            size_t size = sizeof(*this) + sizeof(_swiftMetadataInitializer_NEVER_USE[0]);
            class_ro_t *ro = (class_ro_t *)memdup(this, size);
            ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];
            return ro;
        } else {
            size_t size = sizeof(*this);
            class_ro_t *ro = (class_ro_t *)memdup(this, size);
            return ro;
        }
    }
};

中的这个const ivar_list_t * ivars

image.png 依然没有找到nickName

通过访问ivars

终于找到

这个ivars的列表中里具体都有啥?

image.png
  • 类的方法

打印robaseMethodList

image.png image.png

+walk()类方法找不到了
找元类的方法试下:

image.png

总结:类方法可以理解成元类对象实例方法,因此存在元类

  • 成员变量存放在ivar
  • 属性存放在property,同时也会存一份在ivar,并生成setter、getter方法
  • 对象方法存放在里面
  • 类方法存放在元类里面
  • 利用底层开放的API可以验证以上结论
void testObjc_copyIvar_copyProperies(Class cls) {
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList(cls, &count);
    for (unsigned int i=0; i < count; i++) {
        Ivar const ivar = ivars[i];
        //获取实例变量名
        const char*cName = ivar_getName(ivar);
        NSString *ivarName = [NSString stringWithUTF8String:cName];
        NSLog(@"class_copyIvarList:%@",ivarName);
    }
    free(ivars);

    unsigned int pCount = 0;
    objc_property_t *properties = class_copyPropertyList(cls, &pCount);
    for (unsigned int i=0; i < pCount; i++) {
        objc_property_t const property = properties[i];
        //获取属性名
        NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
        //获取属性值
        NSLog(@"class_copyProperiesList:%@",propertyName);
    }
    free(properties);
}

void testObjc_copyMethodList(Class cls) {
    unsigned int count = 0;
    Method *methods = class_copyMethodList(cls, &count);
    for (unsigned int i=0; i < count; i++) {
        Method const method = methods[i];
        //获取方法名
        NSString *key = NSStringFromSelector(method_getName(method));
        
        NSLog(@"Method, name: %@", key);
    }
    free(methods);
}

void testInstanceMethod_classToMetaclass(Class cls) {
    const char *className = class_getName(cls);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getInstanceMethod(cls, @selector(walk));
    Method method2 = class_getInstanceMethod(metaClass, @selector(fly));

    Method method3 = class_getInstanceMethod(cls, @selector(walk));
    Method method4 = class_getInstanceMethod(metaClass, @selector(fly));
    
    NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
    NSLog(@"%s",__func__);
}

void testClassMethod_classToMetaclass(Class cls) {
    const char *className = class_getName(cls);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getClassMethod(cls, @selector(walk));
    Method method2 = class_getClassMethod(metaClass, @selector(fly));

    Method method3 = class_getClassMethod(cls, @selector(walk));
    Method method4 = class_getClassMethod(metaClass, @selector(fly));
    
    NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
    NSLog(@"%s",__func__);
}

void testIMP_classToMetaclass(Class cls) {
    const char *className = class_getName(cls);
    Class metaClass = objc_getMetaClass(className);

    IMP imp1 = class_getMethodImplementation(cls, @selector(walk));
    IMP imp2 = class_getMethodImplementation(metaClass, @selector(fly));

    IMP imp3 = class_getMethodImplementation(cls, @selector(walk));
    IMP imp4 = class_getMethodImplementation(metaClass, @selector(fly));

    NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
    NSLog(@"%s",__func__);
}

  • 其实直接用clang编译也能看出点东西
  • 关于v@:这个玩意,在苹果开发者文档上也有介绍

相关文章

  • 类的结构探一探

    对象、类、元类、根元类的关系 先温习下这个图先背背图 类的本质 首先准备可调试objc源码,配置可执行的objc源...

  • iOS-isa结构探一探

    本文仅记录笔者的学习过程,只代表笔者个人的理解,如果有错的地方,欢迎各位指正! OC对象的本质 对象继承与NSOb...

  • cache_t结构探一探

    接上文类的结构分析 一.cache_t结构 1.cache_t结构 cache是cache_t类型,那么cache...

  • 一探深绿

    没有说走就走的自由,千亩栀子花地头,亦可去一探深绿。 18点日影斜长。山穿绿妆醉晚霞,水浸倒影疑南天。 栀子林下水...

  • 水库一探

    这水库冬季枯竭的,只剩下一点点水了。 高高的坝体上有一些太阳能装置。这个位置的光照一定最好,可惜今天是烟雨蒙蒙,看...

  • 哪些因素可以定义自己,真的可以吗?

    如何定义自己? 坐在西湖畔,看着微波荡漾的湖水,依稀有游船点缀,一只鸭子潜入水下扎个猛子,继而浮出水面,一探一探脖...

  • brave

    不想无知 不想自私 有一探到底的勇气 无知的勇气

  • 内存对齐探上一探

    写在前面: 在了解内存对齐之前先了解一下各数据类型在内存中的大小,目前我们比较常用的是64位系统,所以我们的研究对...

  • 一探xss攻击

    跨站脚本攻击(cross site scripting),为了与css做区分,简称为xss。顾名思义,就是在别人的...

  • 深度学习一探

    人工智能(AI) AI,即赋予计算机能够自动处理人类世界常规劳动,理解语音或图像,帮助医学诊断等能力。 它...

网友评论

      本文标题:类的结构探一探

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