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

Objective-C,我如何在另一个类中连接一个方法,objective-c,Objective C,Objective-C将其所有方法都保存在一个巨大的哈希表中——那么,难道不可能对该表进行修补,并用我自己的修补方法(然后调用原始方法)替换现有方法吗 我需要一种方法将NSWindow KeyUp方法连接到一个我无法子类化的窗口中,因为它已经被创建了 我需要一些代码或至少一些关键字,以便进一步搜索。当然可以。事实上,您甚至不需要查看哈希表——有标准的API用于此 例如: typedef void (*NSWindow_keyUp__IMP)(NSWindow* self, SEL _cmd, N

Objective-C将其所有方法都保存在一个巨大的哈希表中——那么,难道不可能对该表进行修补,并用我自己的修补方法(然后调用原始方法)替换现有方法吗

我需要一种方法将NSWindow KeyUp方法连接到一个我无法子类化的窗口中,因为它已经被创建了


我需要一些代码或至少一些关键字,以便进一步搜索。

当然可以。事实上,您甚至不需要查看哈希表——有标准的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_);

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

Class object_setClass(id object, Class cls)
参考资料如下:

然后,您的代码应该如下所示:

object_setClass(theWindow, [MyWindowSubclass class]);
您可能遇到的一个问题是,window已经是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@:@");
在任何情况下,都需要定义新的方法实现。看起来可能是这样的(部分由肯尼特负责):


我相信它在目标c中被称为“方法wizzling”。不确定…可能是+1的重复,我没想到。虽然我仍然想知道为什么OP不能在nib文件中更改窗口的标识…他说窗口已经存在,所以我假设它来自一个框架左右。我并不认为这是一个改变框架组件的好设计……原因是我必须对菜单窗口进行子类化,以解决这里描述的问题:我已经更新了我的答案,以处理未知的私有NSWindow类,就像它可能存在于NSMenus中一样。
void new_NSWindow_keyUp_(NSWindow* self, SEL _cmd, NSEvent* evt) {
  [super keyUp: evt];
  ... // do your changes
}