OC中method_setImplementation和method_exchangeImplementations,由于涉及到类方法缓存的清理问题,需要对某一个类的所有子类进行方法缓存清理。但是这两个方法的默认实现是从根类开始遍历,也就是说,如果使用了这两个方法,那么runtime会遍历整个类树,执行方法缓存清理,rumtime工作量很大。
IMP
method_setImplementation(Method m, IMP imp)
{
// Don't know the class - will be slow if RR/AWZ are affected
// fixme build list of classes whose Methods are known externally?
mutex_locker_t lock(runtimeLock);
return _method_setImplementation(Nil, m, imp);
}
static IMP
_method_setImplementation(Class cls, method_t *m, IMP imp)
{
// 此处省略无关代码
// Cache updates are slow if cls is nil (i.e. unknown)
// RR/AWZ updates are slow if cls is nil (i.e. unknown)
// fixme build list of classes whose Methods are known externally?
flushCaches(cls, __func__, [sel, old](Class c){
return c->cache.shouldFlush(sel, old);
});
// 此处省略无关代码
}
void method_exchangeImplementations(Method m1, Method m2)
{
// 此处省略无关代码
// 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, __func__, [sel1, sel2, imp1, imp2](Class c){
return c->cache.shouldFlush(sel1, imp1) || c->cache.shouldFlush(sel2, imp2);
});
// 此处省略无关代码
}
两个方法最终都是使用了flushCaches实现,该方法在未传入cls的情况下,会从NSObject开始遍历,会遍历所有的类,苹果文档里面的备注也说明了这一点
static void flushCaches(Class cls, const char *func, bool (^predicate)(Class))
虽然在遍历的过程中,有了根据缓存判断,需不需要清理的过程,但是如果项目中的类过多,每次设置,效率还是很低下的。
网友评论