Objective-C, как я могу подключить метод в другом классе - PullRequest
3 голосов
/ 07 августа 2010

Objective-C хранит все свои методы в огромной хеш-таблице - так разве не возможно исправить эту таблицу и заменить существующий метод моим собственным исправленным методом (который затем вызывает оригинал)?

Мне нужен способ подключить метод NSWindow KeyUp в окне, которое я не могу подклассить, потому что оно уже создано.

Мне нужен код или хотя бы несколько ключевых слов, которые я могу использовать для дальнейшего поиска.

Ответы [ 2 ]

4 голосов
/ 07 августа 2010

Вы не должны метать методы для этого. Это осуждаемое поведение. Это повлияет на ВСЕ окна в вашем приложении, а не только на то, которое вы хотите изменить. Однако, вместо этого вам следует сделать подкласс 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
}
3 голосов
/ 07 августа 2010

Конечно, это возможно.На самом деле вам даже не нужно заглядывать в хеш-таблицу - для этого есть стандартный 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_);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...