如何使用method_setImplementation()正确调动?

时间:2015-12-29 07:46:12

标签: objective-c objective-c-runtime method-swizzling

我试图了解如何使用method_setImplementation()正确调整。到目前为止,我已经看到两种主要流行的方法混合方法,一种是使用method_setImplementation()而另一种是method_exchangeImplementation

当使用method_exchangeImplementation()进行调配时,您可能会遇到目标类未实现您尝试调整的方法的问题。为了避免在这里使用实现该方法的祖先类并且错误地调整它的问题,首先将实现添加到目标类,然后将swizzledMethod IMP与您的祖先类方法交换以使事情按顺序排列。这对我来说都很有意义......

我的问题是,在使用method_setImplementation时,我们如何处理相同的上述情况?我们不必处理这种情况(直觉上我觉得我们这样做)?如果我们确实需要处理上述情况,示例代码会对我有很大帮助,因为我对如何处理它感到很遗憾。

1 个答案:

答案 0 :(得分:2)

当使用自由函数(也就是常规函数)进行调整时,您需要考虑Objective-C编译器为您想要调整的方法生成的实际方法签名,以及IMP是的事实只是一个函数指针,声明如下:

typedef id (*IMP)(id, SEL, ...);

假设您有一个名为doSomethingWithObject:afterDelay:的方法,它看起来像这样

- (void)doSomethingWithObject:(id)object afterDelay:(NSTimeInterval)delay

编译器生成的相应C函数(有关Objective-C中名称修改的更多信息,请参阅Wikipedia):

void _i_MyClass_doSometingWithObject_afterDelay(id self, SEL _cmd, id object, NSTimeInterval delay)

所以如果你想要交换它,你需要创建一个类似的方法并将指针传递给它:

void swizzledDoSometingWithObjectAfterDelay(id self, SEL _cmd, id object, NSTimeInterval delay) {
    // custom implementation
}

// ....
method_setImplementation(method, (IMP)swizzledDoSometingWithObjectAfterDelay);

如果您想要调配的方法可能在祖先类中声明,并且您只想为您感兴趣的子类调用它,则可以使用class_replaceMethod(),它可以添加或替换方法,只影响目标类:

SEL selector = @selector(doSomethingWithObject:afterDelay:);
IMP newImp = (IMP)swizzledDoSometingWithObjectAfterDelay
Method method = class_getClassMethod([MyClass class], selector);
const char * encoding = method_getTypeEncoding(method);
class_replaceMethod([MyClass class], selector, newIMP, encoding)