iOS 类的结构分析

isa和类的走势图

isa流程图.png

从上图可得知

1、对象的isa 指向类,类的isa指向元类,元类的isa 指向根元类,根元类isa 指向根元类。

2、类继承父类,父类继承根父类,根父类继承 nil。元类继承父元类,父元类继承根元类,根元类继承根父类。

类的结构

新版的objc源码和旧的objc是不一样的,这里主要是分析 新版的objc 源码。
新的源码版本是objc4-818.2

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();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

    void setInfo(uint32_t set) {
        ASSERT(isFuture()  ||  isRealized());
        data()->setFlags(set);
    }

    void clearInfo(uint32_t clear) {
        ASSERT(isFuture()  ||  isRealized());
        data()->clearFlags(clear);
    }
    // 其余源码没有贴出来
}
复制代码

这就是类的主要结构,其中superclass 是父类,cache 是缓存, bits 里面是方法属性代理成员变量

1. cache 的结构

通过源码查看`cache_t` 的结构。可以看出`cache_t`是一个联合体域。
复制代码

struct cache_t {
private:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;
#if __LP64__
            uint16_t                   _flags;
#endif
            uint16_t                   _occupied;
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache;
    };
   
   void incrementOccupied();
public:
    // The following four fields are public for objcdt's use only.
    // objcdt reaches into fields while the process is suspended
    // hence doesn't care for locks and pesky little details like this
    // and can safely use these.
    
    unsigned capacity() const;
    struct bucket_t *buckets() const;
    Class cls() const;
    
    void insert(SEL sel, IMP imp, id receiver);

};

复制代码
JCPerson *p  = [JCPerson alloc]; //class_data_bits_t  cache_t
Class pClass = [JCPerson class];
//        p.name       = @"djc";
//        p.age        = 18;
    
[p sayHello];
[p sayCode];
[p sayMaster];
复制代码

JCPerson通过断点调试lldb 查看

// 拿到类的地址
(lldb) p/x pClass 
(Class) $0 = 0x00000001000082b0 JCPerson 

// 通过便宜地址拿到cache_t
(lldb) p (cache_t *)0x00000001000082c0
(cache_t *) $1 = 0x00000001000082c0

// 查看cache_t 结构
(lldb) p *$1
(cache_t) $2 = {
  _bucketsAndMaybeMask = {
    std::__1::atomic<unsigned long> = {
      Value = 4298515408
    }
  }
   = {
     = {
      _maybeMask = {
        std::__1::atomic<unsigned int> = {
          Value = 0
        }
      }
      _flags = 32804
      _occupied = 0
    }
    _originalPreoptCache = {
      std::__1::atomic<preopt_cache_t *> = {
        Value = 0x0000802400000000
      }
    }
  }
}

// 获得buckets
(lldb) p $2.buckets()
(bucket_t *) $3 = 0x00000001003623d0

(lldb) p *$3
(bucket_t) $4 = {
  _sel = {
    std::__1::atomic<objc_selector *> = (null) {
      Value = nil
    }
  }
  _imp = {
    std::__1::atomic<unsigned long> = {
      Value = 0
    }
  }
}
// 查看sel
(lldb) p $4.sel()
(SEL) $5 = (null)

复制代码
  • 当没有执行sayHello 方法之前 p $4.sel() 得到的是null_occupied0;说明还没有缓存方法。
(lldb) p *$1
(cache_t) $8 = {
  _bucketsAndMaybeMask = {
    std::__1::atomic<unsigned long> = {
      Value = 4311840848
    }
  }
   = {
     = {
      _maybeMask = {
        std::__1::atomic<unsigned int> = {
          Value = 3
        }
      }
      _flags = 32804
      _occupied = 1
    }
    _originalPreoptCache = {
      std::__1::atomic<preopt_cache_t *> = {
        Value = 0x0001802400000003
      }
    }
  }
}

(lldb) p $8.buckets()
(bucket_t *) $10 = 0x000000010101785

(lldb) p $10->sel()
(SEL) $12 = "sayHello"
复制代码
  • 当执行sayHello 之后_occupied1p $10->sel() 返回 (SEL) $12 = "sayHello"
2. cache_t 缓存方法的原理

通过上面lldb调试看得出cache_t在执行方法之后会缓存方法,那么是如何实现的呢?

void cache_t::insert(SEL sel, IMP imp, id receiver)
{
// 部分源码

    // 拿到个数 
    // Use the cache as-is if until we exceed our expected fill ratio.
    mask_t newOccupied = occupied() + 1;
    unsigned oldCapacity = capacity(), capacity = oldCapacity;
    
    // 当没有缓存的时候 分配缓存大小
    if (slowpath(isConstantEmptyCache())) {
        // Cache is read-only. Replace it.
        if (!capacity) capacity = INIT_CACHE_SIZE;
        
        // 分配INIT_CACHE_SIZE=4 的大小
        reallocate(oldCapacity, capacity, /* freeOld */false);
    }
    else if (fastpath(newOccupied + CACHE_END_MARKER <= cache_fill_ratio(capacity))) {
    
    // 缓存存在并且缓存的大小小于3/4 或 7/8 什么都不做
        // Cache is less than 3/4 or 7/8 full. Use it as-is.
    }
#if CACHE_ALLOW_FULL_UTILIZATION
    else if (capacity <= FULL_UTILIZATION_CACHE_SIZE && newOccupied + CACHE_END_MARKER <= capacity) {
        // Allow 100% cache utilization for small buckets. Use it as-is.
    }
#endif
    else {
    // 当缓存存在,并且大于 已经分配的大小时。
    // 重新分配缓存打小,打小为 以前的大小 2倍
    // 最大为 MAX_CACHE_SIZE = 1 << 16 大小
        capacity = capacity ? capacity * 2 : INIT_CACHE_SIZE;
        if (capacity > MAX_CACHE_SIZE) {
            capacity = MAX_CACHE_SIZE;
        }
        reallocate(oldCapacity, capacity, true);
    }
    // 那到当前的方法
    bucket_t *b = buckets();
    
    // 获取下标
    mask_t m = capacity - 1;
    
    // 将当前方法通过hash算法存储
    mask_t begin = cache_hash(sel, m);
    mask_t i = begin;

    // Scan for the first unused slot and insert there.
    // There is guaranteed to be an empty slot.
    
    // 循环 所有方法 ,通过hash 算法存储每个方法
    do {
        if (fastpath(b[i].sel() == 0)) {
            incrementOccupied();
            b[i].set<Atomic, Encoded>(b, sel, imp, cls());
            return;
        }
        if (b[i].sel() == sel) {
            // The entry was added to the cache by some other thread
            // before we grabbed the cacheUpdateLock.
            return;
        }
    } while (fastpath((i = cache_next(i, m)) != begin));

    bad_cache(receiver, (SEL)sel);
#endif // !DEBUG_TASK_THREADS
}
复制代码

3.bits 结构

通过得到类的首地址,然后更具便宜量获得`bits`里面的内容`class_data_bits_t`。
`Person *p = [Person alloc];`
通过`x/4gx Person.class` 获得首地址,然后偏移32位`p (class_data_bits_t *)0x100008220` 得到`bits` 信息,并且得到`class_rw_t`信息。
复制代码
(lldb) x/4gx Person.class
0x100008200: 0x00000001000081d8 0x000000010036a140
0x100008210: 0x00000001003623d0 0x0000802400000000

(lldb) p (class_data_bits_t *)0x100008220
(class_data_bits_t *) $3 = 0x0000000100008200
(lldb) p $3->data()
(class_rw_t *) $4 = 0x00000001000081d8
(lldb) p *$4
(class_rw_t) $5 = {
  flags = 3580144
  witness = 1
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = {
      Value = 4298547440
    }
  }
  firstSubclass = 0x000000010070fd40
  nextSiblingClass = 0x0002e03500000003
}

复制代码
struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
// 有部分代码没有贴出来
...

public:
    
// 成员变量列表
    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_or_rw_ext)->ro;
        }
        return v.get<const class_ro_t *>(&ro_or_rw_ext);
    }

    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_or_rw_ext)->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 *>(&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};
        }
    }
};

复制代码

查看类里面的属性``方法``代理方法下面已查看属性方法为例

// 查看属性方法
(lldb) p $4->properties()
(const property_array_t) $5 = {
  list_array_tt<property_t, property_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x0000000100008220
      }
      arrayAndFlag = 4295000608
    }
  }
}

(lldb) p $5.list
(const RawPtr<property_list_t>) $6 = {
  ptr = 0x0000000100008220
}

(lldb) p $6.ptr
(property_list_t *const) $7 = 0x0000000100008220

(lldb) p *$7
(property_list_t) $7 = {
  entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}

(lldb) p $7.get(0)
(property_t) $8 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享