iOS进阶笔记(一) 对象本质相关源码解读

📣iOS进阶笔记目录


一、Class结构本质


1、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
}

struct objc_object {
    // ISA() assumes this is NOT a tagged pointer object
    Class ISA(bool authenticated = false);
    // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
    Class rawISA();
    // getIsa() allows this to be a tagged pointer object
    Class getIsa();
}

从runtime源码中,可以看出类的本质主要由isa(指向meta-class)、superclass(指向父类指针)、cache(方法缓存)及bits(bits & FAST_DATA_MASK可以找到class_rw_t结构体中获取该类的方法列表、属性列表、协议列表)组成。


2、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;
}
struct class_rw_ext_t {
    DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)
    class_ro_t_authed_ptr<const class_ro_t> ro;
    method_array_t methods;方法列表(二维数组,包括分类方法列表method_list_t、及自身类的方法列表(通过ro获取))
    property_array_t properties;// 属性列表(二维数组)
    protocol_array_t protocols; // 协议列表(二维数组)
    char *demangledName;
    uint32_t version;
};

3、struct class_ro_t结构

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    union {
        const uint8_t * ivarLayout;
        Class nonMetaclass;
    };

    explicit_atomic<const char *> name;
    // With ptrauth, this is signed if it points to a small list, but
    // may be unsigned if it points to a big list.
    void *baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
}

注:isa和superclass相关知识请查阅iOS 进阶笔记(三)一些关键字


二、class_getInstanceSize(Class cls)执行过程


  1. 通过instance的isa找到对应的Class对象

  1. 再到该类对象的struct objc_class结构中调用alignedInstanceSize()函数
size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}

3. alignedInstanceSize(cls)函数内部执行调word_align(unalignedInstanceSize())函数

// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() const {
    return word_align(unalignedInstanceSize());
}

objc-os.h文件中的word_align(x)函数执行操作为:(x + WORD_MASK) & ~WORD_MASK;

static inline uint32_t word_align(uint32_t x) {
    return (x + WORD_MASK) & ~WORD_MASK;
}

对于iOS系统WORD_MASK = 7UL
(x + WORD_MASK) & ~WORD_MASK实质上相当于将对处于堆的对象内存按字节对齐,即先将对象内存地址左移3位,再将地址的最低3位置0。

这也就是为什么所有对象内存地址的低3位值都是0的原因。


  1. unalignedInstanceSize()函数内部执行了objc_class 结构体中成员为class_data_bits_t的结构体中data()函数
// 在struct objc_class: objc_object结构体中定义如下函数
uint32_t unalignedInstanceSize() const {
    ASSERT(isRealized());
    return data()->ro()->instanceSize;
}

data()函数内部执行了:(class_rw_t *)(bits & FAST_DATA_MASK);

// class_data_bits_t 结构体中函数
class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);// 0x00007ffffffffff8UL
}

  1. data()返回类型为class_rw_t结构体指针进一步执行了class_rw_t中的ro()函数,ro()函数实际调用了struct class_ro_tinstanceSize变量值,最终得出该对象占用内存的大小。

函数调用结构图如下:


三、object_getClass (id obj) 执行过程执行过程


1、函数内部调用了 obj->getIsa()

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

2、getIsa() 内部调用了 ISA() 函数

inline Class
objc_object::getIsa() 
{
    // 若不是TaggedPointer类型,则返回对象的isa
    if (fastpath(!isTaggedPointer())) return ISA();

    extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
    uintptr_t slot, ptr = (uintptr_t)this;
    Class cls;
    // ptr 占64位,先右移60位后 & 0x00_00_00_0F
    // 即slot值为ptr的低4位的值
    slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
    cls = objc_tag_classes[slot];
    if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
        slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
        cls = objc_tag_ext_classes[slot];
    }
    return cls;
}

3、ISA() 内部调用了 isa.getDecodedClass(bool authenticated) 函数

inline Class
objc_object::ISA(bool authenticated)
{
    ASSERT(!isTaggedPointer());
    return isa.getDecodedClass(authenticated);
}

4、getDecodeedClass(bool authenticated) 内部调用了 getClass(bool)

inline Class
isa_t::getDecodedClass(bool authenticated) {
    // 对于iOS设备 SUPPORT_INDEXED_ISA = 0
#if SUPPORT_INDEXED_ISA
    if (nonpointer) {
        return classForIndex(indexcls);
    }
    return (Class)cls;
#else
    // 调用了 getClass
    return getClass(authenticated);
#endif
}

5、getClass(bool)内部执行了 bits & ISA_MASK

inline Class
isa_t::getClass(MAYBE_UNUSED_AUTHENTICATED_PARAM bool authenticated) {
#if SUPPORT_INDEXED_ISA
    return cls;
#else

    uintptr_t clsbits = bits;

    // 判断编译器是否支持__has_feature(ptrauth_calls)
#   if __has_feature(ptrauth_calls)
#       if ISA_SIGNING_AUTH_MODE == ISA_SIGNING_AUTH
    // Most callers aren't security critical, so skip the
    // authentication unless they ask for it. Message sending and
    // cache filling are protected by the auth code in msgSend.
    if (authenticated) {
        // Mask off all bits besides the class pointer and signature.
        clsbits &= ISA_MASK;// 可以看出ISA()本质是 bits & ISA_MASK
        if (clsbits == 0)
            return Nil;
        clsbits = (uintptr_t)ptrauth_auth_data((void *)clsbits, ISA_SIGNING_KEY, ptrauth_blend_discriminator(this, ISA_SIGNING_DISCRIMINATOR));
    } else {
        // If not authenticating, strip using the precomputed class mask.
        clsbits &= objc_debug_isa_class_mask;
    }
#       else
    // If not authenticating, strip using the precomputed class mask.
    clsbits &= objc_debug_isa_class_mask;
#       endif

#   else
    clsbits &= ISA_MASK;// 可以看出ISA()本质是 bits & ISA_MASK
#   endif

    return (Class)clsbits;
#endif
}

</br>

6、当object_getClass(id obj)中obj为Instance对象时,bit & ISA_MASK 地址则为其类对象地址;
当obj为类对象时,bits & ISA_MASK 地址则为其meta-claas对象地址;
当obj为meta-class时,bits & ISA_MASK 地址则为meta-class基类对象的地址


以上


----------End------------

posted @ 2021-08-04 20:52  ITRyan  阅读(140)  评论(0编辑  收藏  举报