赞
踩
objc_msgSend(object, selector)
从 selector, 到 class_rw_t 里面的 method_t ( Method )
method_t 里面:
Method 的实现
struct method_t {
SEL name;// 函数名
const char *types; // 编码,( 返回值类型,参数类型 )
MethodListIMP 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; }
};
};
取方法分两种情况:
第一次取
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;
// 在方法数组里面找
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 *>()->methods;
} else {
return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
}
}
method_array_t 里面,去找 Method
方法数组的实现
class method_array_t :
public list_array_tt<method_t, method_list_t>
{
typedef list_array_tt<method_t, method_list_t> Super;
public:
method_array_t() : Super() { }
method_array_t(method_list_t *l) : Super(l) { }
method_list_t * const *beginCategoryMethodLists() const {
return beginLists();
}
method_list_t * const *endCategoryMethodLists(Class cls) const;
method_array_t duplicate() {
return Super::duplicate<method_array_t>();
}
};
然后进入
struct method_t
以后取,走方法缓存
方法缓存 cache_t, 用散列表 ( 哈希表 ) 来缓存曾经调用过的方法,
可以提高方法的查找速度
cache_t 的实现
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
explicit_atomic<struct bucket_t *> _buckets; // 散列表
explicit_atomic<mask_t> _mask; // 散列表的长度
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied; // 已经缓存的方法数量
cache_t 中,找到 IMP
struct bucket_t {
private:
// IMP-first is better for arm64e ptrauth and no worse for arm64.
// SEL-first is better for armv7* and i386 and x86_64.
#if __arm64__
explicit_atomic<uintptr_t> _imp; // 函数的内存地址
explicit_atomic<SEL> _sel; // SEL 作为 Key
#else
explicit_atomic<SEL> _sel;
explicit_atomic<uintptr_t> _imp;
#endif
交换方法method_exchangeImplementations
+ (void)load{
Method tap = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method listen = class_getInstanceMethod(self, @selector(listenAction:to:forEvent:));
method_exchangeImplementations(tap, listen);
}
这样搞一下,发生了什么?
原来
@selector(sendAction:to:forEvent:)
对应
Method: sendAction:to:forEvent: 的实现
另一边
@selector(listenAction:to:forEvent:)
对应
Method: listenAction:to:forEvent: 的实现
交换后:
@selector(sendAction:to:forEvent:)
对应
Method: listenAction:to:forEvent: 的实现
另一边
@selector(listenAction:to:forEvent:)
对应
Method: sendAction:to:forEvent: 的实现
交换方法:就是交换一下实现指针,并刷新了方法缓存
void method_exchangeImplementations(Method m1, Method m2)
{
if (!m1 || !m2) return;
mutex_locker_t lock(runtimeLock);
// 交换一下实现指针 IMP
IMP m1_imp = m1->imp;
m1->imp = m2->imp;
m2->imp = m1_imp;
// RR/AWZ updates are slow because class is unknown
// Cache updates are slow because class is unknown
// fixme build list of classes whose Methods are known externally?
// 清空方法缓存
flushCaches(nil);
adjustCustomFlagsForMethodChange(nil, m1);
adjustCustomFlagsForMethodChange(nil, m2);
}
清空缓存:
void _objc_flush_caches(Class cls)
{
{
mutex_locker_t lock(runtimeLock);
flushCaches(cls);
if (cls && cls->superclass && cls != cls->getIsa()) {
flushCaches(cls->getIsa());
} else {
// cls is a root class or root metaclass. Its metaclass is itself
// or a subclass so the metaclass caches were already flushed.
}
}
if (!cls) {
// collectALot if cls==nil
#if CONFIG_USE_CACHE_LOCK
mutex_locker_t lock(cacheUpdateLock);
#else
mutex_locker_t lock(runtimeLock);
#endif
cache_collect(true);
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。