05.MethodSwizzling的问题
使用 Method Swizzling 编程就好比切菜时使用锋利的刀,一些人因为担心切到自己所以害怕锋利的刀具,可是事实上,使用钝刀往往更容易出事,而利刀更为安全。 Method swizzling 可以帮助我们写出更好的,更高效的,易维护的代码。但是如果滥用它,也将会导致难以排查的bug。
相关方法
class_replaceMethod
替换类方法的定义*
method_exchangeImplementations
交换 2 个方法的实现这里相当于调用了两次
method_setImplementation
点进方法的注释里面可以看到相关注释
即 A <-> B
method_setImplementation
设置 1 个方法的实现即 A -> B
注意点: 用
method_setImplementation
的话单方面设置实现有的场景挺实用functionA
设置了functionB
的实现 那么项目中使用functionA
和functionB
的地方就会有同样的实现 但是如果用method_exchangeImplementations
的话,就会有不同的实现
看一下 RNSwizzle 的封装
方法交换不是自动的
我所见过的使用method swizzling实现的方法在并发使用时基本都是安全的。95%的情况里这都不会是个问题。通常你替换一个方法的实现,是希望它在整个程序的生命周期里有效的。也就是说,你会把 method swizzling 修改方法实现的操作放在一个加号方法 +(void)load里,并在应用程序的一开始就调用执行。你将不会碰到并发问题。假如你在 +(void)initialize初始化方法中进行swizzle,那么……rumtime可能死于一个诡异的状态。
改变不是自己的代码
这是swizzling的一个问题。我们的目标是改变某些代码。swizzling方法是一件灰常灰常重要的事,当你不只是对一个NSButton类的实例进行了修改,而是程序中所有的NSButton实例。因此在swizzling时应该多加小心,但也不用总是去刻意避免。
想象一下,如果你重写了一个类的方法,而且没有调用父类的这个方法,这可能会引起问题。大多数情况下,父类方法期望会被调用(至少文档是这样说的)。如果你在swizzling实现中也这样做了,这会避免大部分问题。还是调用原始实现吧,如若不然,你会费很大力气去考虑代码的安全问题。
命名冲突
命名冲突贯穿整个Cocoa的问题. 我们常常在类名和类别方法名前加上前缀。不幸的是,命名冲突仍是个折磨。但是swizzling其实也不必过多考虑这个问题。我们只需要在原始方法命名前做小小的改动来命名就好,比如通常我们这样命名
这段代码运行正确,但是如果my_setFrame: 在别处被定义了会发生什么呢? 这个问题不仅仅存在于swizzling,这里有一个替代的变通方法:
看起来不那么Objectice-C了(用了函数指针),这样避免了selector的命名冲突。 最后给出一个较完美的swizzle方法的定义:
交换方法影响了方法调用
项目中调用不同方法名的问题 上面讨论过了
交换的顺序
多个有继承关系的类的对象swizzle时,先从父对象开始
这样才能保证子类方法拿到父类中的被swizzle的实现
在+(void)load中swizzle不会出错,就是因为load类方法会默认从父类开始调用
Last updated