Ios 不使用“呼叫超级”;超级";关键词
我想“实现”Xcode 3中的“修复并继续功能” 上下文: 其主要思想是: 当我需要“快速修复某些东西”时,我不是在重新编译project。我正在编译带有“更新”方法实现的小型Ios 不使用“呼叫超级”;超级";关键词,ios,objective-c,iphone,objective-c-runtime,Ios,Objective C,Iphone,Objective C Runtime,我想“实现”Xcode 3中的“修复并继续功能” 上下文: 其主要思想是: 当我需要“快速修复某些东西”时,我不是在重新编译project。我正在编译带有“更新”方法实现的小型Attacker类,将其加载到内存中,并替换运行时执行不正确的方法。 我认为这种方法比整个项目重新编译的速度更快 完成修复后,我只是将攻击者类方法的源代码复制到受害者类 问题 目前,我不知道如何正确地在攻击者类中调用[super…] 例如,我有一个受害者班 @interface VictimClass : UIView @
Attacker类
,将其加载到内存中,并替换运行时执行不正确的方法。
我认为这种方法比整个项目重新编译的速度更快
完成修复后,我只是将攻击者类
方法的源代码复制到受害者类
问题
目前,我不知道如何正确地在攻击者类中调用[super…]
例如,我有一个受害者班
@interface VictimClass : UIView @end
@implementation VictimClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
@end
@interface AttackerClass : NSObject @end
@implementation AttackerClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[self setupPrettyBackground];
}
@end
....
// EXCHANGE IMPLEMENTATIONS
Method m = class_getInstanceMethod([AttackerClass class], @selector(drawRect:));
const char * types = method_getTypeEncoding(m);
IMP attackerImp = method_getImplementation(m);
class_replaceMethod([VictimClass class], @selector(drawRect:), attackerImp, types);
// Invoking drawRect on Victim
VictimClass * view = /* */;
[view setNeedsDisplay];
此时,当调用drawRect:
方法时,这将导致异常,因为将在NSObject类上调用drawRect:
,而不是在UIView类上
所以,我的问题是,如何正确地在AttackClass中调用[super drawRect:
,才能在运行时正确地交换实现
其主要思想是提供一种方法,用攻击者的类方法正确替换受害者类中的任何方法。通常,您不知道,受害者类的超类
更新:替换已添加的实现代码。但是,当NSObject没有该方法时,为什么需要为超类NSObject调用draw rect方法呢?只是别这么做。。。仅在VictimClass drawrect中调用它假设您正在进行的运行时更改涉及修改超类,则必须执行以下操作:
@implementation AttackerClass
-(void) drawRect:(CGRect)rect
{
if( [super respondsToSelector:@selector(drawRect:)] )
{
[super drawRect:rect];
}
[self setupPrettyBackground];
}
@end
这将检查超类是否“知道”drawRect:
,并且在super
没有drawRect:
选择器的情况下不调用它
因此,当超类为NSObject
时,将不会发送drawRect:
消息。当您在运行时将其更改为UIView
时(无论您的原因是什么),可以安全地发送消息。您必须
获取receivers类(例如,使用对象\u getClass(rcv)
)
然后获取它的超类(使用class\u getSuperclass(class)
)
然后获取它的实现(使用class\u getMethodImplementation(超类,sel)
)
然后打电话给小鬼
完成
如果得到nil或NULL,请在任何步骤停止
哦,所有这些看起来都很愚蠢。但我认为,这个问题只是缺乏背景,看不出这种黑客行为的动机
[更新]
对未来读者的解释:
super
关键字在编译时解析。因此,当在运行时更改方法时,它不是预期的事情。要在运行时注入到某个对象(及其类层次结构)中的方法必须通过上述运行时执行超级调用。一种方法是使用objc_msgSendSuper。您的方法-[AttackClass drawRect:将具有以下实现:
- (void)drawRect:(CGRect)rect {
struct objc_super superTarget;
superTarget.receiver = self;
superTarget.class = object_getClass(self);
objc_msgSendSuper(&superTarget, @selector(drawRect:), rect);
[self setupPrettyBackground];
}
仍然不明白,什么是运行时替换方法。为什么要将AttackerClass的超类从NSObject更改为UIView?他不。。。他只有两个独立的类我喜欢你在问题中如何使用攻击者类和受害者类。。非常好的类比,简化了一个相对复杂的场景。你知道如何在不陷入超级递归调用的情况下完成上述操作吗?看到我的问题的更新你是对的。。。但事实是,当你编写代码时,你已经知道你的超类没有这个方法。。。不需要调用它,也不需要检查…@meronix同意,但他暗示他正在运行时更改超类,并且在超类设置完成之前不想发送drawRect:
消息。我仍然需要调用超类。。。方法实现。你的方法就是不打超级电话。但我需要用同样的方式来调用它,就像在方法替换之前一样。这没有任何意义。您不能将消息发送到不响应所述消息并期望其工作的超类。在运行时避免异常的唯一方法是首先不将消息发送给超类。如果你要替换一个方法而不是替换超类,这仍然是安全的,而且是正确的做法。。。我会努力做到这一点。然后告诉你结果。这可能是正确的答案。谢谢,伙计,通过使用这种行为,你实际上可以模仿“超级”呼叫。顺便说一句,我用了你的答案。。工作得很有魅力!:)