复制方法 IMP 以进行多个方法混合
我设置了一个类,理想情况下将读取传入的任何类的方法,然后在运行时将它们全部映射到单个选择器,然后将它们转发到原始选择器。
这现在确实有效,但我一次只能使用一种方法。问题似乎是,一旦我调整第一个方法,我用于捕获和转发该方法的 IMP 现在已与其他方法 IMP 交换。任何进一步的尝试都会搞砸,因为他们使用新交换的 IMP 来替换其他 IMP。
1)所以我有MethodA、MethodB和CustomCatchAllMethod。
2)我将 MethodA 与 CustomCatchAllMethod 交换。 MethodA->CustomCatchAllMethod、CustomCatchAllMethod->MethodA
3)现在我也尝试用 CustomCatchAllMethod 交换到 MethodB,但由于 CustomCatchAllMethod 现在 = MethodA,MethodB 变成 MethodA 和 MethodA->MethodB。
那么,如何为每个我想要拦截的新选择器获取/复制 IMP 的新实例呢?
这是上述流程的粗略模型:
void swizzle(Class classImCopying, SEL orig){
SEL new = @selector(catchAll:);
Method origMethod = class_getInstanceMethod(classImCopying, orig);
Method newMethod = class_getInstanceMethod(catchAllClass,new);
method_exchangeImplementations(origMethod, newMethod);
}
//In some method elsewhere
//I want this to make both methodA and methodB point to catchAll:
swizzle(someClass, @selector(methodA:));
swizzle(someClass, @selector(methodB:));
I have a class set up that ideally will read the methods of any class passed in and then map all of them to on single selector at runtime before forwarding them off to their original selector.
This does work right now, but I can only do it for one method at a time. The issue seems to be that once I swizzle the first method, my IMP to catch and forward the method has now been swapped with that other methods IMP. Any further attempts at this screw up because they use newly swapped IMP to replace the others.
1)So I have MethodA, MethodB, and CustomCatchAllMethod.
2)I swap MethodA with CustomCatchAllMEthod. MethodA->CustomCatchAllMethod, CustomCatchAllMethod->MethodA
3)Now I try to swap to MethodB with CustomCatchAllMethod as well, but since CustomCatchAllMethod now = MethodA, MethodB becomes MethodA and MethodA->MethodB.
So how do I get/copy a new instance of my IMP for each new selector I want to intercept?
Here's a rough mockup of the above flow:
void swizzle(Class classImCopying, SEL orig){
SEL new = @selector(catchAll:);
Method origMethod = class_getInstanceMethod(classImCopying, orig);
Method newMethod = class_getInstanceMethod(catchAllClass,new);
method_exchangeImplementations(origMethod, newMethod);
}
//In some method elsewhere
//I want this to make both methodA and methodB point to catchAll:
swizzle(someClass, @selector(methodA:));
swizzle(someClass, @selector(methodB:));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这种常见的方法调配模式仅在您想要拦截一种方法与另一种方法时才有效。在您的情况下,您基本上是在移动
catchAll:
的实现,而不是将其插入到任何地方。为了正确地做到这一点,你必须使用:
但这给你带来了一个问题:如何转发到原始实现?
这就是原始模式使用
exchangeImplementations
的目的。在您的情况下,您可以:
IMP
的表格,或者catchAll:
构建对它们的调用请注意,当您想通过相同的方法转发所有内容时,您只能处理相同数量的方法。
That common method-swizzling pattern only works when you want to intercept one method with one other. In your case you are basically moving the implementation for
catchAll:
around instead of inserting it everywhere.To properly to this you'd have to use:
This leaves you with one problem though: how to forward to the original implementation?
That is what the original pattern used
exchangeImplementations
for.In your case you could:
IMP
s around orcatchAll:
Note that you can only handle methods of the same arity when you want to forward everything through the same method.
您可以使用块捕获原始IMP,获取块的IMP并将其设置为方法的实现。
You can capture original IMP with block, get block's IMP and set it as implementation of method.