2012-02-12 14 views
7

czy mimo to monitoruje wywołanie metody obiektu specjalnego i otrzymuje powiadomienie? Chciałbym, aby funkcja "Observer" została wywołana, gdy wywoływana jest metoda [object someMethod]. Wiem, że mogę monitorować zmianę wartości obiektu za pomocą celu c KVO, ale nie oznacza to, że stos wywołań (które funkcje) spowodował zmianę wartości obiektu. Czy jest coś podobnego do KVO, ale do metod, w których mogę monitorować wywołania funkcji? Wszelkie sugestie, jak wdrożyć taką funkcję, jeśli nie jest to możliwe z istniejącą strukturą? Dzięki!Cel C - otrzymasz powiadomienie, gdy metoda nazywa się

Odpowiedz

1

W dokumencie related question Bill Bumgarner zauważa (gra słów nie przeznaczonych), że nie jest to możliwe w przypadku ogólnym.

Sugerowałbym, że jeśli potrzebujesz znać rozmówcę z powodu swojego projektu interfejsu API, lepszym rozwiązaniem jest zmodyfikowanie metody, aby pobrać parametr "nadawca" (jak wiele metod ramowych, w tym każda IBAction, do) . Wtedy to osoba wywołująca jest odpowiedzialna za przekazanie siebie do metody.

Ma to dodatkową zaletę, pozwalając na stosowanie bardziej złożonych wzorów. Mogłem sobie wyobrazić na przykład obiekt proxy, który zgodnie z prawem chciał przekazać inny obiekt zamiast siebie. (Oczywiście trzeba to zrobić ostrożnie i rozważnie.)

9

Zakładam, że nie kontrolujesz implementacji klasy, której metodę chcesz przechwycić, a więc zmieniając API jako @Conrad Shultz sugeruje, że nie jest to wykonalne. Istnieje kilka innych podejść, które przychodzą na myśl.

Pierwszą z nich jest metoda swizzling. Działa to w ten sposób, że dodajesz metodę z tym samym podpisem do klasy za pomocą kategorii, a następnie zamieniasz implementacje metody, którą chcesz przechwycić, oraz metodę, którą dodałeś. Dodana metoda wywoła wszystkie haki, które chcesz przed i/lub po wywołaniu do "siebie". Ponieważ zamieniasz implementacje, wywołanie "samego siebie" wywołuje oryginalną metodę. Istnieje wiele dobrych objaśnień dotyczących metody przekręcania się. Here's one.

Inną opcją może być owinięcie obiektu w NSProxy i przekazywanie połączeń za pomocą -forwardInvocation. Znowu istnieje wiele zasobów wyjaśniających szczegółowo proxy i odsyłacz inwokacji, więc nie będę go tutaj ponownie. Here's one. To podejście jest ograniczone, ponieważ musisz mieć niezbędny dostęp do zamiany w swoim proxy dla prawdziwego obiektu. Jeśli obiekt jest tworzony prywatnie w ramach niektórych interfejsów API, to podejście nie będzie użyteczne.

Innym podejściem jest zrobienie tego, co robi KVO. Wartość kluczowa Obserwacja działa poprzez utworzenie podklasy klasy w środowisku wykonawczym, a następnie wykonanie funkcji o nazwie isa -sizzling w celu zmiany klasy istniejącej instancji na nową podklasę dynamiczną. Nie ma powodu, dla którego nie można utworzyć podklasy generowanej przez środowisko wykonawcze klasy, której metoda instancji ma zostać przechwycona, a następnie zaimplementować wywołanie tej metody w podklasie generowanej przez środowisko wykonawcze do innych haków przed i/lub po wywołaniu klasy superklasy. (real) wdrożenie metody. To może pozwolić ci łatwiej przechwycić więcej niż jedną metodę, ale nie będzie prostego sposobu na przechwycenie dowolnych metod z dowolnymi sygnaturami, ponieważ musisz wymyślić sposób na wywołanie swoich haków bez naruszania stos, a następnie wektor do podstawowej realizacji. Przechwycenie dowolnych metod z arbitralnymi podpisami w ten sposób prawdopodobnie wymagałoby napisania trampolin w zespole, a następnie wzywania do rzeczywistej implementacji, na przykład objc_msgSend. Oto good article on runtime subclassing.

Dla perspektywy historycznej: istniała również funkcja o nazwie poseAsClass, która również by pozwalała na to, ale została usunięta, myślę, że od czasów SnowLeopard-owh, więc prawdopodobnie nie jest uruchamiana.

Każda z tych opcji będzie miała wpływ na wydajność i będzie niezwykle "sprytna". Nie mówię, żebym poklepał się po plecach - nie wymyśliłem żadnego z nich, tylko je zwróciłem. Zauważyłem jednak przez te wszystkie lata, że ​​kiedy rozwiązanie wydaje się zbyt "sprytne", jest to znak, że zmierzam do ewentualnej katastrofy. Inaczej mówiąc, jeśli API, z którym pracujesz, nie daje możliwości przechwycenia tych wywołań metod, prawdopodobnie jest to znak, że powinieneś podejść do problemu z innej perspektywy. Ale twój przebieg może się oczywiście różnić.

Powiązane problemy