【发布时间】:2020-10-28 09:19:35
【问题描述】:
我在玩方法注入,但在这个上烧了我的手指。
有两个班级,猫和狗。狗试图通过调动speak 方法来找出猫的秘密。狗确实发现猫有一个catSecret 方法,但无法动态注入替代方法。为什么?
Dog端的相关方法是
- ( NSString * ) speak
{
return @"Woof";
}
- ( NSString * ) wannabeCat
{
return @"Meow?";
}
+ ( BOOL ) resolveInstanceMethod:( SEL ) aSelector
{
NSString * s = NSStringFromSelector ( aSelector );
if ( [s containsString:@"Secret"] )
{
NSLog ( @"Oops - the cats have a %@", s );
IMP m = [Dog.class methodForSelector:@selector ( wannabeCat )];
class_addMethod ( Dog.class, aSelector, m, "@@:" );
NSLog ( @"\tAdded" );
return YES;
}
else
{
NSLog ( @"Skipping %@", s );
return [super resolveInstanceMethod:aSelector];
}
}
编辑
之前我尝试在 forwardingTargetForSelector 方法中做同样的事情,但在来自 Cy-4AH 的 cmets 之后,我将其移至 resolveInstanceMethod,这似乎是正确的地方。
狗希望在此之后,Dog 类有一个添加的方法,但这不起作用。它仍然以'-[Dog catSecret]: unrecognized selector sent to instance 消息终止。我的问题是 - 为什么这不起作用?
在Cat 方面,这是相关的部分。
- ( NSString * ) catSecret
{
return @"scratch";
}
- ( NSString * ) speak
{
return [NSString stringWithFormat:@"Miaau (%@)", self.catSecret]
}
我希望在 Dog 端动态注入 catSecret 选择器和 wannabeCat 实现。
输出如下所示
2020-10-28 12:05:12.613324+0200 Swizzle[4786:119045] Oops - the cats have a catSecret
2020-10-28 12:05:12.613357+0200 Swizzle[4786:119045] Added
2020-10-28 12:05:12.613434+0200 Swizzle[4786:119045] Skipping _forwardStackInvocation:
2020-10-28 12:05:12.613482+0200 Swizzle[4786:119045] -[Dog catSecret]: unrecognized selector sent to instance 0x1006b2730
【问题讨论】:
-
forwardingTargetForSelector是selector的转发目标,意思是找一个能做selector的人。要为选择器动态添加实现,您需要resolveInstanceMethod: -
是的 - 我希望在
forwardingTargetForSelector中注入该方法,这就是为什么我从那里返回self...但我会尝试在resolveInstanceMethod:中进行...跨度> -
试试把你的测试代码放在
dyspatch_asynch里面,可能你要测试的时间太早了 -
我将代码移至
+resolveInstanceMethod:,然后添加它没问题。我认为这是这样做的方法,谢谢,但它仍然以无法识别的选择器异常告终。我记录了它想要解析的选择器,并在+resolveInstanceMethod中获得了一个_forwardStackInvocation:,我不知道如何处理。我想我只是在寻找一种动态注入然后使用方法的方法,而我尝试的方法不起作用。我见过的例子通常注入一些已知的方法,但在这里。方法是动态发现的。
标签: objective-c objective-c-runtime