超级没有“超级”关键字调用超级
我想'实现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 class
的Victim class
。
更新 :replace添加的实现代码。
你不得不
- 获取接收者类(例如
object_getClass(rcv)
) - 然后获得它的超类(与
class_getSuperclass(class)
) - 然后得到它的实现(用
class_getMethodImplementation(superclass, sel)
) - 然后调用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器的情况下不调用它。
因此,当超类是NSObject
, drawRect:
消息将不会被发送。 在运行时将其更改为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中调用它