【问题标题】:Objective-C, how can i hook up a method in another classObjective-C,我如何连接另一个类中的方法
【发布时间】:2010-08-07 09:24:46
【问题描述】:

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

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

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

【问题讨论】:

标签: objective-c


【解决方案1】:

您不应该为此混用方法。这是已弃用的行为。这将影响您应用程序中的所有窗口,而不仅仅是您想要更改的窗口。但是,您应该做的是已经将 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@:@");

在任何情况下,您都需要定义新的方法实现。它可能看起来像这样(部分由 KennyTM 提供):

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

【讨论】:

  • +1,我没想到。虽然我仍然想知道为什么 OP 不能只在 nib 文件中更改窗口的身份......
  • 他说窗口已经存在,所以我假设它来自一个框架左右。并不是说我认为这是改变框架组件的任何好的设计......
  • 原因是我必须子类化菜单窗口来解决我在这里描述的问题:stackoverflow.com/questions/3429749/…
  • 我已经更新了我的答案以应对未知的私有 NSWindow 类,就像它可能存在于 NSMenus 一样。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 2015-07-10
    • 2015-08-01
    • 2020-09-02
    • 2013-03-05
    • 1970-01-01
    相关资源
    最近更新 更多