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
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.)
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ć.
- 1. otrzymasz powiadomienie, gdy UITextField stanie się FirstResponder
- 2. Wykonaj (magiczną) metodę, gdy istniejąca metoda nazywa się
- 3. Wykonywanie akcji niestandardowej, gdy dana metoda wyszydzania nazywa się
- 4. Metoda delegata CALayer drawLayer nie nazywa się
- 5. To, co się nazywa po metoda onConfigurationchanged()
- 6. WebView: WebViewClient.onPageStarted metoda nie nazywa się
- 7. Zaktualizuj numer identyfikacyjny, gdy otrzymasz powiadomienie push, gdy aplikacja nie jest otwarta.
- 8. Uzyskaj polecenie lua, gdy funkcja c nazywa się
- 9. Która metoda SendAsync nazywa gdy HttpClientHandler jest przekazywana do HttpClient
- 10. Windows - otrzymasz ostrzeżenie, gdy plik zostanie utworzony
- 11. Interfejs prywatny a metoda prywatna - cel c
- 12. Funkcja iAd nie jest wyświetlana asynchronicznie, gdy jej metoda delegata nazywa się
- 13. MVC4 Custom HandleErrorAttribute, metoda w global.asax nie nazywa się
- 14. Jak otrzymać powiadomienie, gdy powiadomienie zostanie zgłoszone?
- 15. Dlaczego nazywa się onBlur?
- 16. textFieldDidBeginEditing: nie nazywa się
- 17. Sprawdź metoda nazywa się lub nie w jednostce testowej
- 18. Rhino Mocks - Ustaw właściwość, jeśli metoda nazywa się
- 19. Metoda nazywa się -viewWillLayoutSubviews niewytłumaczalny sposób przebiega dwukrotnie
- 20. Dlaczego metoda członkiem klasy nazywa się przed Konstruktora
- 21. Dlaczego nazywa się "String"?
- 22. CAEmitterLayer nie renderuje, gdy -renderInContext: z superlayer nazywa się
- 23. Co się nazywa, gdy rzucasz tablicę obiektów do tablicy łańcuchów?
- 24. Co się nazywa, gdy mówię "catch (Exception e) {}" w Javie?
- 25. Jak się nazywa, gdy ludzie próbują nadużywać wzorców projektowych?
- 26. textViewDidEndEditing nie nazywa się
- 27. Curl_http_done: nazywa się przedwczesny
- 28. XmlHttpRequest.onload nie nazywa się
- 29. AjaxComplete nazywa się często
- 30. Fragment onResume nie nazywa się