1

我试图了解如何正确使用method_setImplementation(). 到目前为止,我在网上看到了两种主要流行的调酒方法,一种是使用method_setImplementation()while 其他 levarages method_exchangeImplementation

使用 swizzling 时,method_exchangeImplementation()您可能会遇到目标类未实现您尝试 swizzle 的方法的问题。为了避免祖先类实现该方法并错误地调配该方法时出现问题,您首先将一个实现添加到您的目标类,然后将 swizzledMethodIMP与您的祖先类方法交换以使事情井井有条。这一切对我来说都很有意义......

我的问题是我们如何处理与 swizzling 时相同的上述情况method_setImplementation?我们不需要处理这个案子吗(直觉上我觉得我们需要处理)?如果我们确实需要处理上述案例示例代码将对我有很大帮助,因为我不知道如何处理它。

4

1 回答 1

3

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

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

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

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

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

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)
于 2015-12-29T08:00:48.643 回答