我曾听人说过,这种方法是一种危险的做法。就连“swizzling”这个名字也暗示着这是一种欺骗。

方法Swizzling正在修改映射,以便调用选择器A将实际调用实现b。这样做的一个用途是扩展闭源类的行为。

我们是否可以将风险正式化,以便决定是否使用swizzling的人可以做出明智的决定,是否值得他们尝试这样做。

E.g.

命名冲突:如果类后来扩展其功能以包含您添加的方法名,将会导致大量的问题。通过合理地命名swizzled方法来降低风险。


当前回答

It's not the swizzling itself that's really dangerous. The problem is, as you say, that it's often used to modify the behavior of framework classes. It's assuming that you know something about how those private classes work that's "dangerous." Even if your modifications work today, there's always a chance that Apple will change the class in the future and cause your modification to break. Also, if many different apps do it, it makes it that much harder for Apple to change the framework without breaking a lot of existing software.

其他回答

我觉得最大的危险是完全无意中产生许多不必要的副作用。这些副作用可能会以“bug”的形式出现,从而导致你走上错误的道路去寻找解决方案。根据我的经验,危险在于难以辨认、令人困惑和令人沮丧的代码。有点像有人在c++中过度使用函数指针。

方法变换在单元测试中非常有用。

它允许您编写一个模拟对象,并使用该模拟对象而不是实际对象。代码保持干净,单元测试具有可预测的行为。假设您想要测试一些使用CLLocationManager的代码。你的单元测试可以混合startUpdatingLocation,这样它就会给你的委托提供一组预定的位置,而你的代码就不必改变了。

It's not the swizzling itself that's really dangerous. The problem is, as you say, that it's often used to modify the behavior of framework classes. It's assuming that you know something about how those private classes work that's "dangerous." Even if your modifications work today, there's always a chance that Apple will change the class in the future and cause your modification to break. Also, if many different apps do it, it makes it that much harder for Apple to change the framework without breaking a lot of existing software.

虽然我使用了这种技巧,但我想指出:

It obfuscates your code because it can cause un-documented, though desired, side effects. When one reads the code he/she may be unaware of the side effect behavior that is required unless he/she remembers to search the code base to see if it has been swizzled. I'm not sure how to alleviate this problem because it is not always possible to document every place where the code is dependent upon the side effect swizzled behavior. It can make your code less reusable because someone who finds a segment of code which depends upon the swizzled behavior that they would like to use elsewhere cannot simply cut and paste it into some other code base without also finding and copying the swizzled method.

你可能会得到一些奇怪的代码,比如

- (void)addSubview:(UIView *)view atIndex:(NSInteger)index {
    //this looks like an infinite loop but we're swizzling so default will get called
    [self addSubview:view atIndex:index];

来自实际生产代码,与一些UI魔法有关。