代码之家  ›  专栏  ›  技术社区  ›  Lothar

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

  •  3
  • Lothar  · 技术社区  · 14 年前

    Objective-C将它的所有方法都保存在一个巨大的哈希表中—那么,是否应该修补这个表并用我自己的修补方法(然后调用原始方法)替换现有方法呢?

    我需要一种方法来连接一个窗口,我不能子类,因为它已经创建了nswindowkeyup方法。

    2 回复  |  直到 10 年前
        1
  •  3
  •   kennytm    14 年前

    例如:

    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_);
    
        2
  •  5
  •   Max Seelemann    14 年前

    你不应该为这个吹毛求疵的方法。这是不赞成的行为。这将影响应用程序中的所有窗口,而不仅仅是要更改的窗口。但是,您应该做的是将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]);
    

    关于你的问题 根据经验,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@:@");
    

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