一、isa指针
1、在Objective-C对象的分类中说过无论是instance对象、class对象还是meta-class对象中都有一个isa指针。不同的是instance对象的isa指针指向class对象;class对象中的isa指向meta-class对象;meta-class对象指向基类的meta-class对象。不同的是
- 在ARM64架构之前,isa就是一个普通的指针,存储者class对象、meta-class对象的内存地址
- 在ARM64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多信息
- ARM64架构下的isa指针类型
isa_t isa;
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if SUPPORT_PACKED_ISA
// extra_rc must be the MSB-most field (so it matches carry/overflow flags)
// nonpointer must be the LSB (fixme or get rid of it)
// shiftcls must occupy the same bits that a real class pointer would
// bits + RC_ONE is equivalent to extra_rc + 1
// RC_HALF is the high bit of extra_rc (i.e. half of its range)
// future expansion:
// uintptr_t fast_rr : 1; // no r/r overrides
// uintptr_t lock : 2; // lock for atomic property, @synch
// uintptr_t extraBytes : 1; // allocated with extra bytes
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct {
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19;
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
struct {
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8;
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
};
# else
# error unknown architecture for packed isa
# endif
// SUPPORT_PACKED_ISA
#endif
#if SUPPORT_INDEXED_ISA
# if __ARM_ARCH_7K__ >= 2
# define ISA_INDEX_IS_NPI 1
# define ISA_INDEX_MASK 0x0001FFFC
# define ISA_INDEX_SHIFT 2
# define ISA_INDEX_BITS 15
# define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
# define ISA_INDEX_MAGIC_MASK 0x001E0001
# define ISA_INDEX_MAGIC_VALUE 0x001C0001
struct {
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t indexcls : 15;
uintptr_t magic : 4;
uintptr_t has_cxx_dtor : 1;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 7;
# define RC_ONE (1ULL<<25)
# define RC_HALF (1ULL<<6)
};
# else
# error unknown architecture for indexed isa
# endif
// SUPPORT_INDEXED_ISA
#endif
}
- nonpointer
0:是代表普通的指针,存储着class、meta-class对象的内存地址
1:代表优化过,使用位域存储更多的信息
- has_assoc
是否有设置过关联对象,如果没有,释放时会更快
- has_cxx_dtor
是否有C++的析构函数(.cxx_destruct),如果没有,释放的更快
- shiftcls
存储着Class、Meta-Class对象的内存地址信息
- magic
用于在调试时分辨对象是否未完成初始化
- weakly_referenced
是否有被弱引用指向过,如果没有,释放时会更快
- deallocating
对象是否正在释放
- has_sidetable_rc
引用计数器是否过大无法存储在isa中,如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
- extra_rc
里面存储的值是引用计数器减1
2、通过代码来测试看一下
0x000001a1b7ab6ea1
11010000110110111101010110110111010100001
- 最后一位是1,所以代表优化过,使用位域存储更多的信息
0x000001a1b7ab6ea3
11010000110110111101010110110111010100011
- 倒数第二位是1,表示有设置关联对象
二、Class的结构
1、从源码来看Class的定义
typedef struct objc_class *Class;
struct objc_class : objc_object {
// Class ISA;
//指向 父类
Class superclass;
//方法缓存
cache_t cache; // formerly cache pointer and vtable
//bits是一个用于获取具体类的信息
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
//
class_rw_t *data() {
return bits.data();
}
.
.
.
}
- 2、(bits & FAST_DATA_MASK)会获得类的详细信息结构体,但是这是一个可读可写结构体struct class_rw_t
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
//类的原始信息,只读类型
const class_ro_t *ro;
//存储着类的方法列表是一个二维数组(分类的方法列表<method_list_t<method_t>>;类的方法列表<method_list_t<method_t>>)
method_array_t methods;
//存储着类的属性列表是一个二维数组(分类的属性列表<property_list_t<property_t>>;类的方法列表<property_list_t<property_t>>)
property_array_t properties;
//存储着类的协议列表是一个二维数组(分类的协议列表<protocol_list_t<protocol_ref_t>>;类的方法列表<protocol_list_t<protocol_ref_t>>)
protocol_array_t protocols;
.
.
.
}
- 3、类的原始数据结构struct class_ro_t 结构体
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_t>
method_list_t * baseMethodList;
//存储类的协议列表是一个数组<protocol_ref_t>
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
//存储类的属性列表是一个数组<property_t>
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
}
-
4、三者的关系如下
- a)通过Class对象中的bits与FAST_DATA_MASK掩码进行&操作,就可以获取到当前类的详细信息
- b)ro是类中的原始信息,不包含分类或者动态绑定的一些属性
- c)class_rw_t结构体中的methods、properties、protocols都是二维数组,他们把分类中的methods、properties、protocols当一个元素存储到其中;把ro中的baseMethodList、baseProtocols、baseProperties作为另一个元素存储到其中。
-
5、class_rw_t里面的methods、properties、protocols是二维数组,是可读可写的,包含了类的初始内容、分类的内容
三、Method_t
method_t是对方法\函数的封装
1、 method_t结构体
struct method_t {
SEL name;//函数名
const char *types;//返回值类型 参数类型...
IMP imp;//指向函数的指针
struct SortBySELAddress :
public std::binary_function<const method_t&,
const method_t&, bool>
{
bool operator() (const method_t& lhs,
const method_t& rhs)
{ return lhs.name < rhs.name; }
};
};
- 1、SEL代表方法\函数名,一般叫做选择器,底层结构类似char *
- 可以通过@selector()和sel_registerName()获得
- 可以通过sel_getName()和NSStringFromSelector()转成字符串
- 不同类中相同名字的方法,所对应的方法选择器是相同的
typedef struct objc_selector *SEL;
返回值 参数1 参数2 . . . 参数n
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
四、方法缓存结构体cache_t
struct cache_t {
//缓存方法的数组
struct bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
public:
struct bucket_t *buckets();
mask_t mask();
mask_t occupied();
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void initializeToEmpty();
mask_t capacity();
bool isConstantEmptyCache();
bool canBeFreed();
static size_t bytesForCapacity(uint32_t cap);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void expand();
void reallocate(mask_t oldCapacity, mask_t newCapacity);
struct bucket_t * find(cache_key_t key, id receiver);
static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
}
- bucket_t结构体中存储者方法;方法名作为_key,方法地址作为_imp
struct bucket_t {
private:
cache_key_t _key;
IMP _imp;
public:
inline cache_key_t key() const { return _key; }
inline IMP imp() const { return (IMP)_imp; }
inline void setKey(cache_key_t newKey) { _key = newKey; }
inline void setImp(IMP newImp) { _imp = newImp; }
void set(cache_key_t newKey, IMP newImp);
}
-
小结:Class内部结构中有个方法缓存(cache_t),用山列表(哈希表)来缓存曾经调用过的方法,可以提高方法的查找速度