【发布时间】:2016-08-17 18:28:30
【问题描述】:
我在搞乱方法调配,想在执行method_exchangeImplementations 后调用原始函数。我为此设置了两个项目。
第一个项目是应用程序的主项目。该项目包括应用程序的所有逻辑。注意originalMethodName 在视图加载时被调用。
@implementation ViewController
- (void)originalMethodName
{
NSLog(@"REAL %s", __func__);
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"REAL %s", __func__);
[self originalMethodName];
}
@end
第二个项目仅包含 swizzling 的代码。我有一个方法swizzle_originalMethodName,其中包括我想注入到主应用程序中的代码,调用originalMethodName 函数。
@implementation swizzle_ViewController
- (void)swizzle_originalMethodName
{
NSLog(@"FAKE %s", __func__);
}
__attribute__((constructor)) static void initializer(void)
{
NSLog(@"FAKE %s", __func__);
Class c1 = objc_getClass("ViewController");
Class c2 = [swizzle_ViewController class];
Method m1 = class_getInstanceMethod(c1, @selector(originalMethodName));
Method m2 = class_getInstanceMethod(c2, @selector(swizzle_originalMethodName));
method_exchangeImplementations(m1, m2);
}
@end
调酒器工作得很好(如下面的输出所示),但现在我希望能够从swizzle_originalMethodName 调用originalMethodName
2016-08-17 14:18:51.765 testMacOS[7295:1297055] FAKE initializer
2016-08-17 14:18:51.822 testMacOS[7295:1297055] REAL -[ViewController viewDidLoad]
2016-08-17 14:18:51.822 testMacOS[7295:1297055] FAKE -[swizzle_ViewController swizzle_originalMethodName]
我尝试使用NSInvocation,但没有任何运气。任何想法我做错了什么?
Class c1 = objc_getClass("ViewController");
Method m1 = class_getInstanceMethod(c1, @selector(originalMethodName));
NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:method_getTypeEncoding( m1)];
NSInvocation *originalInvocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[originalInvocation invoke];
【问题讨论】:
-
直接拨打
[self swizzle_originalMethodName];怎么样?该选择器应在交换后指向原始实现。 -
这是天才。不知道为什么我没有想到。我仍然收到一个错误,我不知道如何解决它。
-[ViewController swizzle_originalMethodName]: unrecognized selector sent to instance 0x7ff72974a670 -
啊,对……你在不同的班级里混日子。我需要考虑一下。
-
这个问题在 SO 上出现过几次,但从未得到完全回答。一些答案对 swizzling 进行了令人难以置信的深度,但从未包含任何经过测试并证明可以工作的代码。这让我疯狂了好几个小时。哈哈
标签: objective-c swizzling method-swizzling