超级没有“超级”关键字调用超级

我想'实现Xcode 3中的“修复和继续function”。

背景

主要想法是:当我需要“快速修复”时,我不会重新编译,项目。 我正在用'更新'的方法实现编译一个小的Attacker class ,将它加载到内存中,并replaceVictimClass在运行时有incorrect的方法。 我认为这种方法将更快地完成项目重新编译。

当我完成修复时,我只是将Attacker class方法的源文件复制到Victim class

问题

目前,我不知道如何在Attacker类中正确调用[super ...]

例如,我有VictimClass

 @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:方法将被调用时,这将导致exception,因为drawRect:将在NSObject类上调用,而不是在UIView类上调用

那么,我的问题是,如何在AttackerClass中正确调用[super drawRect:] ,有可能在运行时正确交换实现?

主要思想是通过Attacker的类方法提供一种方法来正确replaceVictim类中的任何方法。 一般来说,你不知道, Victim classVictim class

更新 :replace添加的实现代码。

你不得不

  1. 获取接收者类(例如object_getClass(rcv)
  2. 然后获得它的超类(与class_getSuperclass(class)
  3. 然后得到它的实现(用class_getMethodImplementation(superclass, sel)
  4. 然后调用imp。

DONE

如果你有nil或NULL,可以在任何一步停止。

哦,这一切似乎很愚蠢。 但是我认为这个问题只是缺乏背景来看待这种黑客的动机。

[更新]

对未来读者的解释:

super关键字在编译时parsing。 因此,在运行时更改方法时,它并不是有意的事情。 打算在运行时注入某个对象(及其类层次结构)的方法必须通过运行时执行超级调用,如上所述。

假设您正在进行的运行时修改涉及到修改超类,您将不得不这样做:

 @implementation AttackerClass -(void) drawRect:(CGRect)rect { if( [super respondsToSelector:@selector(drawRect:)] ) { [super drawRect:rect]; } [self setupPrettyBackground]; } @end 

这将检查超类“知道” drawRect:并且在super没有drawRect:select器的情况下不调用它。

因此,当超类是NSObjectdrawRect:消息将不会被发送。 在运行时将其更改为UIView (无论您的理由是什么),可以安全地发送消息。

一种方法是使用objc_msgSendSuper。 你的方法– [AttackerClass 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]; } 

但是当NSObject没有得到这个方法时,为什么你需要为超类NSObject调用drawRect方法呢? 只是不要这样做…只是在VictimClass drawrect中调用它