methodList数据结构
realizeClassWithoutSwift -> methodizeClass(Attach categories)
// Install methods and properties that the class implements itself.
method_list_t *list = ro->baseMethods();
通常查看里面的具体内容使用的lldb调试命令是
**p $2.get(0).big()**,查看get函数
Element& getOrEnd(uint32_t i) const {
ASSERT(i <= count);
return *PointerModifier::modify(*this, (Element *)((uint8_t *)this + sizeof(*this) + i*entsize()));
}
Element& get(uint32_t i) const {
ASSERT(i < count);
return getOrEnd(i);
}
所以能得出method_list_t里面存储的是指针
分类加载是否需要排序
由上面我们知道methods是一个指针数据,指针本身并没有排序的说法。所以分类本身并不需要排序
auto const methods = cls->data()->methods();
for (auto mlists = methods.beginLists(),
end = methods.endLists();
mlists != end;
++mlists)
{
method_t *m = search_method_list_inline(*mlists, sel);
if (m) return m;
}
Exention vs Category
category:
- 专门给类添加新的方法
- 不能给类添加成员属性,添加了成员变量也无法获取到
- 可以通过runtime给类添加属性
- 分类中用property修饰的属性,只会生成getter和setter的申明,不能生成带_的成员变量和方法实现
extention:
- 可以说是特殊的分类,匿名分类
- 可以给类添加成员属性但是私有变量
- 可以给类添加方法也是私有方法
类扩展
在main中写一个类扩展。clang一下找到main.cpp文件打开。在主类的方法列表里面找到了类扩展里面的方法和set/get方法。
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[18];
} _OBJC_$_INSTANCE_METHODS_LGStudent __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
18,
{(struct objc_selector *)"ext_instanceMethod", "v16@0:8", (void *)_I_LGStudent_ext_instanceMethod},
{(struct objc_selector *)"ext_name", "@16@0:8", (void *)_I_LGStudent_ext_name},
{(struct objc_selector *)"setExt_name:", "v24@0:8@16", (void *)_I_LGStudent_setExt_name_},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_LGStudent_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_LGStudent_setName_},
{(struct objc_selector *)"age", "i16@0:8", (void *)_I_LGStudent_age},
{(struct objc_selector *)"setAge:", "v20@0:8i16", (void *)_I_LGStudent_setAge_},
{(struct objc_selector *)"ext_name", "@16@0:8", (void *)_I_LGStudent_ext_name}}
}
我们知道,分类可以影响主类的加载流程,那么类扩展呢,同样在源码realizeClassWithoutSwift处调试
不难得出,扩展的方法已经添加到方法列表里面去了。
分类
我们在分类中添加属性,会报出这样的警告,需要我们手动的实现set和get方法
- (void)setCate_name:(NSString *)cate_name{
/**
1: 对象
2: 标识符
3: value
4: 策略
*/
objc_setAssociatedObject(self, "cate_name", cate_name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)cate_name{
return objc_getAssociatedObject(self, "cate_name");
}
关联对象objc_setAssociatedObject设值
objc_setAssociatedObject -> _object_set_associative_reference
关联的对象的本质是存储这个属性
bool isFirstAssociation = false;
{
// 1.创建一个AssociationsManager管理类
AssociationsManager manager;
// 2.获取唯一的全局静态哈希map
AssociationsHashMap &associations(manager.get());
// 3.判断插入的关键值是否存在 比如”name“
if (value) {
// 4.创建一个空的 ObjectAssociationMap去获取查询的键值对
// 5.try_emplace 如果没有发现这个key(name)就创建一个空的TheBucket进去 然后返回
// 6.try_emplace 标记对象存在关联对象
// refs_result的数据结构 first{Ptr,End} second = true
auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
if (refs_result.second) {
/* it's the first association we make */
isFirstAssociation = true;
}
/* establish or replace the association */
/* refs_result.first->second {
Buckets = nil
NumEntries = 0
NumTombstones = 0
NumBuckets = 0
} */
auto &refs = refs_result.first->second;
// 7.try_emplace 用当前association(策略和value)组成的ObjectAssociation替换原来BucketT的空置
// 8.try_emplace 标记ObjectAssociationMap的first=false
auto result = refs.try_emplace(key, std::move(association));
/* refs_result.first->second {
Buckets = 0x0000000101313590
NumEntries = 1
NumTombstones = 0
NumBuckets = 4
} */
// 前后对比发现buckets已经赋值上了
if (!result.second) {
association.swap(result.first->second);
}
} else {
// 4.根据DisguisedPtr找到AssociationsHashMap中的迭代查询器
auto refs_it = associations.find(disguised);
if (refs_it != associations.end()) {
auto &refs = refs_it->second;
auto it = refs.find(key);
if (it != refs.end()) {
association.swap(it->second);
//5.清理
refs.erase(it);
//6.如果插入为空 也清理
if (refs.size() == 0) {
associations.erase(refs_it);
}
}
}
}
}
LookupBucketFor算法
try_emplace -> LookupBucketFor与寻找cache里面的bucket算法一致
template<typename LookupKeyT>
bool LookupBucketFor(const LookupKeyT &Val,
const BucketT *&FoundBucket) const {
// ...
// 找到bucket的index
unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);
unsigned ProbeAmt = 1;
while (true) {
const BucketT *ThisBucket = BucketsPtr + BucketNo;
// Found Val's bucket? If so, return it. 命中就返回
if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
FoundBucket = ThisBucket;
return true;
}
//如果找到一个空的bucket,则该键不存在于集合中。插入它并返回默认值
if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
// If we've already seen a tombstone while probing, fill it in instead
// of the empty bucket we eventually probed to.
FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
return false;
}
if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
!FoundTombstone)
FoundTombstone = ThisBucket; // Remember the first tombstone found.
if (ValueInfoT::isPurgeable(ThisBucket->getSecond()) && !FoundTombstone)
FoundTombstone = ThisBucket;
if (ProbeAmt > NumBuckets) {
FatalCorruptHashTables(BucketsPtr, NumBuckets);
}
BucketNo += ProbeAmt++;
BucketNo &= (NumBuckets-1); // 再哈希
}
}
关联对象objc_getAssociatedObject取值
objc_getAssociatedObject -> _object_get_associative_reference
{
//1.创建一个AssociationsManager管理类
AssociationsManager manager;
//2.获取唯一的全局静态哈希map
AssociationsHashMap &associations(manager.get());
//3.根据DisguisedPtr找到AssociationsHashMap中的迭代查询器
AssociationsHashMap::iterator i = associations.find((objc_object *)object);
/*
associations.end() = {
Ptr = 0x0000000100673cc0
End = 0x0000000100673cc0
}
*/
if (i != associations.end()) {
/*
i->second = {
Buckets = 0x0000000101b3c4f0
NumEntries = 1
NumTombstones = 0
NumBuckets = 4
}
*/
//4.如果这个迭代查询器不是最后一个获取ObjectAssociationMap
ObjectAssociationMap &refs = i->second;
// 5.找到ObjectAssociationMap的迭代查询器
ObjectAssociationMap::iterator j = refs.find(key);
if (j != refs.end()) {
association = j->second;
// 6.返回经过属性修饰符修饰的value
association.retainReturnedValue();
}
}
}
总结
其实就是两层哈希map,存取的时候两层处理(类似于二维数组)
补充
构造函数和析构函数
class AssociationsManager {
using Storage = ExplicitInitDenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap>;
static Storage _mapStorage;
public:
AssociationsManager() { AssociationsManagerLock.lock(); }
~AssociationsManager() { AssociationsManagerLock.unlock(); }
AssociationsHashMap &get() {
return _mapStorage.get();
}
static void init() {
_mapStorage.init();
}
};
AssociationsManager manager就是调用了构造函数AssociationsManager()
出了作用域自动调用析构函数~AssociationsManager()