如何正确调配 method_setImplementation()?
How to correctly swizzle with method_setImplementation()?
我正在尝试了解如何使用 method_setImplementation()
正确调配。到目前为止,我在网上看到了两种主要流行的 method swizzle 方法,一种是使用 method_setImplementation()
,另一种是使用 method_exchangeImplementation
.
使用 method_exchangeImplementation()
调配时,您可能会遇到目标 class 未实现您尝试调配的方法的问题。为了避免祖先 class 实现该方法并错误地调配该方法时出现问题,您首先向目标 class 添加一个实现,然后将 swizzledMethod IMP
与您的祖先 classes 方法使事情井然有序。这一切对我来说都很有意义...
我的问题是,当使用 method_setImplementation
调配时,我们如何处理上述相同的情况?我们是否不必处理这种情况(直觉上我觉得我们需要处理)?如果我们确实需要处理上述案例,示例代码将对我有很大帮助,因为我不知道如何处理它。
使用自由函数(a.k.a 常规函数)进行调配时,您需要考虑 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 中声明,并且您只想为您感兴趣的子 class 调整它,您可以使用 class_replaceMethod(),它添加或替换方法,并且只影响目标 class:
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)
我正在尝试了解如何使用 method_setImplementation()
正确调配。到目前为止,我在网上看到了两种主要流行的 method swizzle 方法,一种是使用 method_setImplementation()
,另一种是使用 method_exchangeImplementation
.
使用 method_exchangeImplementation()
调配时,您可能会遇到目标 class 未实现您尝试调配的方法的问题。为了避免祖先 class 实现该方法并错误地调配该方法时出现问题,您首先向目标 class 添加一个实现,然后将 swizzledMethod IMP
与您的祖先 classes 方法使事情井然有序。这一切对我来说都很有意义...
我的问题是,当使用 method_setImplementation
调配时,我们如何处理上述相同的情况?我们是否不必处理这种情况(直觉上我觉得我们需要处理)?如果我们确实需要处理上述案例,示例代码将对我有很大帮助,因为我不知道如何处理它。
使用自由函数(a.k.a 常规函数)进行调配时,您需要考虑 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 中声明,并且您只想为您感兴趣的子 class 调整它,您可以使用 class_replaceMethod(),它添加或替换方法,并且只影响目标 class:
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)