isa和类的走势图
从上图可得知
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
;_occupied
为0
;说明还没有缓存方法。
(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
之后_occupied
为1
,p $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