Objective-C,我如何在另一个类中挂接一个方法

时间:2010-08-07 09:24:47

标签: objective-c

Objective-C将所有方法保存在一个巨大的哈希表中 - 所以不应该修补这个表并用我自己的修补方法(然后调用原始方法)替换现有方法吗?

我需要一种方法来将NSWindow KeyUp方法挂钩在一个窗口中,我无法将其子类化,因为它已经创建了。

我需要一些代码或至少一些我可以用来进一步搜索的关键字。

2 个答案:

答案 0 :(得分:4)

你不应该为此调整方法。这是不推荐使用的行为。这将影响您应用中的所有窗口,而不仅仅是您想要更改的窗口。但是,您应该做的是将NSWindow子类化,然后在运行时更改该窗口的类。这可以使用此运行时函数来完成:

Class object_setClass(id object, Class cls)

参考文献:http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/doc/uid/TP40001418-CH1g-SW12

您的代码应如下所示:

object_setClass(theWindow, [MyWindowSubclass class]);

可能体验的问题上,该窗口已经是NSWindow的子类。如果是这种情况,有更复杂的方法来实现这一目标。您可以在运行时动态构造一个类。这是一些更多的代码。鉴于该窗口是目标窗口:

Class newWindowClass = objc_allocateClassPair([window class], "MyHackyWindowSubclass", 0);
Method upMethod = class_getInstanceMethod(newWindowClass, @selector(keyUp:));
method_setImplementation(upMethod, new_NSWindow_keyUp_);
object_setClass(window, newWindowClass);

我不完全确定这不会改变超类的实现。文档有点不明确。但是,你仍然应该尝试一下。如果它不起作用,请将第二行和第三行替换为:

class_replaceMethod(newWindowClass, @selector(keyUp:), new_NSWindow_keyUp_, "v@:@");

无论如何,您需要定义新的Method实现。它可能看起来像那样(部分来自KennyTM):

void new_NSWindow_keyUp_(NSWindow* self, SEL _cmd, NSEvent* evt) {
  [super keyUp: evt];
  ... // do your changes
}

答案 1 :(得分:3)

当然有可能。实际上,您甚至不需要查看哈希表 - 这是标准的API。

例如:

typedef void (*NSWindow_keyUp__IMP)(NSWindow* self, SEL _cmd, NSEvent* evt);
static NSWindow_keyUp__IMP original_NSWindow_keyUp_;

void replaced_NSWindow_keyUp_(NSWindow* self, SEL _cmd, NSEvent* evt) {
  NSLog(@"Entering keyUp:. self = %@, event = %@", self, evt);
  original_NSWindow_keyUp_(self, _cmd, evt);
  NSLog(@"Leaving keyUp:. self = %@, event = %@", self, evt);
}

...

Method m = class_getInstanceMethod([NSWindow class], @selector(keyUp:));
original_NSWindow_keyUp_ = method_setImplementation(m, replaced_NSWindow_keyUp_);