在oc的runtime机制内有一类方法是可以用来实现类间的方法替换。解决了我们实际开发中诸多常规手段所无法解决的问题。关于Method Swizzling,这里有一篇介绍基本用法的文章
场景
最近出于某种原因,我翻阅了MJRefresh的源码,其中该库就使用了方法交换策略。
在其UICollectionView
和UITableView
的类别里我发现该库使用了以下代码。于是分析了下其为何如此做的原因。
使用源码如下:
分析
这里先介绍下load
的方法的执行方式。load
方法是NSObject的方法,NSObject则是oc里大部分类的基类。只要类被添加到runtime中,load的方法均会被调用,而且只会自动被调用一次(除非你自行有调用了次方法,不过一般不会这样做)。其调用方式是执行顺序是 类 -> 子类 ->分类 ,例如A继承与B会先执行B的load
再执行A的load
,如果分类实现了load
方法也是一样会先执行类的load
再执行此类的分类里的load
方法。因此,此方法是不会被覆盖。
MJRefresh为了替换oc类tableview大专栏 Swizzling的使用e>和
collectionview
的reloadData以达到调用其自定义的mj_reloadDataBlock
,因此实现了分别定义了类别UITableView(MJRefresh)
和UICollectionView(MJRefresh)
并重写了类方法load
。在load
方法里MJRefresh做了一件事情就是使用runtime里的method_exchangeImplementations
方法来实现用mj_reloadData
替换tableview
和collectionview
里的reloadData
方法。
在mj_reloadData
的方法里我们看到其为了该方法能既能执行原有的reloadData
方法又能执行mj_reloadDataBlock
,他先调用了[self mj_reloadData]
然后有调用了mj_reloadDataBlock
。由于方法被交换过,因此此处的[self mj_reloadData]
会调用reloadData
方法并不会造成死循环,同时也达到了其目的调用原有的reloadData
方法。
但是这里我也发现了一个问题,既然方法交换了,如果你调用了[self mj_reloadData]
方法则会变成调用reloadData
方法,那样岂不是会达到效果?在这里MJRefresh为了不让你这样做,则是将mj_reloadData
做为私有方法,没有公开API,你是无法直接调用到的(当然你想调用还是调用的到的,这里就不多做讨论)。
总结
从此处设计,能看出来method_exchangeImplementations
的runtime方法的使用场景以及如何运用的思路。在此做了分析记录,也为以后如果碰到一些类似场景提供一些新的解决思路和方式。