类的原理分析(一)

96 阅读2分钟

定义一个类

定义一个类,并从这个类开始讲起

@interface GPerson : NSObject {
    NSString *address;
}

@property (nonatomic, copy) NSString *name;

- (void)eat;

+ (void)sleep;

@end

类的定义

typedef struct objc_class *Class;

objc_class继承于objc_object

struct objc_class : objc_object {
 
    // Class ISA;              // 继承于objc_object
    Class superclass;          // 父类
    cache_t cache;             // 缓存信息
    class_data_bits_t bits;    // 包含属性列表,方法列表等信息
    ......
 }

如何探索bits中的内容?通过内存平移的方式我们来看一下bits中的内容,其中继承于objc_object所以其中有一个isa指针占8字节,superclass占8字节,cache_t是结构体类型,cache_t的16字节

properties

x/6gx拿到首地址

image.png

当前对象的地址0x10060df60,通过平移32得到0x10060df80p (class_data_bits_t *)0x10060df80

image.png

现在我们拿到了class_data_bits_t,在class_data_bits_t中有一个data()方法,来获取一个class_rw_t类型的数据

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

p $11->data()得到这个class_rw_t

image.png p *$12看看这个结构中都有些什么

image.png 在当前的信息中并没有看到我们想象中的关于类的相关信息,查看class_rw_t的定义

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:
    ...... 中间省略部分代码

    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 *>(&ro_or_rw_ext)->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->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 *>(&ro_or_rw_ext)->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->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 *>(&ro_or_rw_ext)->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
        }
    }
};

此时我们就看到了我们经常讨论的东西methodspropertiesprotocols,接下来通过这个方式来查看类中定义的属性

p $12.properties()

image.png

查看list属性,类型是property_list_t

image.png

继续查看ptr以及内容

image.png

其中count就是类中定义的属性的个数,通过p $12.get(0)查看到定义的name属性

image.png

这里property_t的结构

struct property_t {
    const char *name;
    const char *attributes;
};

另外我们还定义了一个成员变量address但并不在properties中

methods

同样的步骤我们可以拿到methods

image.png

image.png

不同的是我们此时再用get方法获取到的是空的,因为此时的method_t

struct method_t {
    static const uint32_t smallMethodListFlag = 0x80000000;

    method_t(const method_t &other) = delete;

    // The representation of a "big" method. This is the traditional
    // representation of three pointers storing the selector, types
    // and implementation.
    struct big {
        SEL name;
        const char *types;
        MethodListIMP imp;
    };
    ......
}

获取到的method_t调用big方法

image.png

依次打印会发现并没有类方法

总结

那么实例方法和成员变量到底在什么地方呢?第二篇再来探索。