2009-08-22 5 views

Odpowiedz

10

W skrócie, nie można.

Mogłeś w Objective-C 1.0 ABI/API poprzez:

OBJC_EXPORT void class_removeMethods(Class, struct objc_method_list *) OBJC2_UNAVAILABLE; 

ale funkcja została usunięta w Objective-C 2.0, ponieważ usunięcie metody jest prawie nigdy nie jest prawidłowa odpowiedź. Z pewnością nie dość często, aby uzasadnić koszty poniesione przez wspieranie wspomnianej funkcji.

Również usunięty z ABI ObjC2.0 była możliwość bezpośredniego dostępu do struktur klasy/metody. Są teraz nieprzezroczyste, aby można je było zmienić w przyszłości bez łamania kompatybilności binarnej.

Można jednak użyć niestandardowego serwera proxy, który zmienia zestaw metod, na które odpowiada. Zobacz dokumentację dla klasy NSProxy; http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSProxy_Class/Reference/Reference.html

Oczywiście to pytanie nasuwa pytanie "Co próbujesz zrobić?". Takie meta-programowanie w locie jest nietypowe. Po utworzeniu klasy nie jest zwykle pożądane zmienianie zestawu metod, na które reaguje przy założeniu, że poprzednie wystąpienia mogą nadal zależeć od wspomnianych metod.

+0

Odpowiedzią na "dlaczego" jest to, że jestem zainteresowany napisaniem kodu, który pokaże, co się dzieje, gdy KVC jest używane. Dodając i usuwając metody w czasie wykonywania, mogłem pozwolić użytkownikowi na zbadanie wpływu posiadania różnych kombinacji metod. Doszedłem do wniosku, że jedynym sposobem, w jaki można to zrobić, jest pomylenie z wewnętrznymi; a Objective-C 2.0 powstrzymuje to za wszelką cenę, z wyjątkiem hakerów. –

+0

Może trochę za późno, ale: Może w twojej próbce możesz dynamicznie tworzyć podklasy w czasie wykonywania, które odpowiadają na żądane metody. Zamiast usuwać metodę, możesz po prostu utworzyć nową podklasę swojej klasy bazowej, która nie ma tej metody. –

+0

Kolejny przypadek, w którym konieczne jest usunięcie metody: w testach jednostkowych czasami trzeba wykluczyć metody z istniejących klas. Struktura OCMock pozwala to zrobić, ale samo OCMock ma trudności z przywróceniem klasy po indywidualnym teście, ponieważ nie może usunąć metod. Może zastąpić IMP istniejącej metody za pomocą kodu pośredniczącego, ale jeśli metoda była w klasie nadrzędnej, musi dodać kod pośredniczący w podklasie, a następnie nie może się go pozbyć. Aby odpowiedzieć na pytanie "Co próbujesz zrobić?" Pytanie: Całkowicie otrzymałem "opiniotwórcze oprogramowanie", ale moim zdaniem środowisko wykonawcze Apple nie powinno być tym. –

13

Nie można dokładnie "usunąć" metody, ale można uzyskać ten sam efekt, co usunięcie, dzięki temu, że metoda przekierowuje wszystko do ścieżki przekazywania wiadomości (kod, który ostatecznie zadzwoni pod numer -forwardInvocation:). Istnieją dwa sposoby, aby to osiągnąć:

  1. _objc_msgForward(), zadeklarowane w /usr/include/objc/message.h ale nie ujęte w dokumentacji online, mogą być używane jako IMP dla metody, którą próbujesz usunąć. Ponieważ jest to nieudokumentowane, może być uznane za prywatne lub nieobsługiwane.
  2. Możesz zadzwonić pod numer class_getMethodImplementation() za pomocą selektora, o którym wiesz, że nie istnieje, i użyć wyniku jako metody IMP dla metody, którą próbujesz usunąć. Na podstawie dokumentacji, to powinien mieć taki sam efekt jak w pierwszej opcji:

Funkcją wskaźnik zwracany może być funkcją wewnętrznego środowiska wykonawczego zamiast rzeczywistej implementacji metody. Na przykład jeśli instancje klasy nie odpowiadają na selektor, zwracany wskaźnik funkcji będzie częścią mechanizmu przesyłania komunikatów programu wykonawczego.

W obu przypadkach, staje się tak proste, jak:

method_setImplementation(methodToRemove, forwardingIMP); 

pamiętać, że to w zasadzie blokowania wszelkich nadklasy implementacje, więc trzeba być bardziej ostrożnym jeśli nadklasą może mieć ważny implementacja, którą chcesz zachować. W takim przypadku można uzyskać IMP z nadklasy lub coś podobnego.

Powiązane problemy