这里是一些 Method Swizzling的陷阱:
Method swizzling is not atomic
Changes behavior of un-owned code
Possible naming conflicts
Swizzling changes the method arguments
The order of swizzles matters
Difficult to understand (looks recursive)
Difficult to debug
@interfaceNSView : NSObject-(void)setFrame:(NSRect)frame;@end@implementationNSView(MyViewAdditions)-(void)my_setFrame:(NSRect)frame{// do custom work [selfmy_setFrame:frame];}+(void)load{[selfswizzle:@selector(setFrame:)with:@selector(my_setFrame:)];}@end
这段代码运行正确,但是如果my_setFrame: 在别处被定义了会发生什么呢?
这个问题不仅仅存在于swizzling,这里有一个替代的变通方法:
12345678910111213141516171819
@implementationNSView(MyViewAdditions)staticvoidMySetFrame(idself,SEL_cmd,NSRectframe);staticvoid(*SetFrameIMP)(idself,SEL_cmd,NSRectframe);staticvoidMySetFrame(idself,SEL_cmd,NSRectframe){// do custom work SetFrameIMP(self,_cmd,frame);}+(void)load{[selfswizzle:@selector(setFrame:)with:(IMP)MySetFramestore:(IMP*)&SetFrameIMP];}@end
What happens when the method on NSButton is swizzled? Well most swizzling will ensure that it’s not replacing the implementation of setFrame: for all views, so it will pull up the instance method. This will use the existing implementation to re-define setFrame: in the NSButton class so that exchanging implementations doesn’t affect all views. The existing implementation is the one defined on NSView. The same thing will happen when swizzling on NSControl (again using the NSView implementation).
When you call setFrame: on a button, it will therefore call your swizzled method, and then jump straight to the setFrame: method originally defined on NSView. The NSControl and NSView swizzled implementations will not be called.
But what if the order were:
Since the view swizzling takes place first, the control swizzling will be able to pull up the right method. Likewise, since the control swizzling was before the button swizzling, the button will pull up the control’s swizzled implementation of setFrame:. This is a bit confusing, but this is the correct order. How can we ensure this order of things?
Again, just use load to swizzle things. If you swizzle in load and you only make changes to the class being loaded, you’ll be safe. The load method guarantees that the super class load method will be called before any subclasses. We’ll get the exact right order!
这段贴了原文,硬翻译太拗口……总结一下就是:多个有继承关系的类的对象swizzle时,先从父对象开始。 这样才能保证子类方法拿到父类中的被swizzle的实现。在+(void)load中swizzle不会出错,就是因为load类方法会默认从父类开始调用。