Nie jestem pewien, jak to ująć, i nie mogłem znaleźć odpowiedzi z powodu mojej niezdolności do znalezienia słów, aby wyrazić to, czego szukam. (!)
W Javie robiłem coś takiego (nie pamiętam):
JPanel myButton = new JPanel("Press me"){
public void add(JComponent component){
//override add method
}
};
Ale nie mogłem znaleźć, jak to zrobić w Objective-C. To, co znalazłem podczas wyszukiwania, to kategorie i dziwne symbole ^{} ...
Jak więc nadpisać metody w nowo utworzonym obiekcie?
(Na przykład zastąp -(BOOL)isEqual;
w nowo utworzonym NSString*
?)
Przepraszam, jeśli pytanie jest trochę niejasne..
EDYTOWAĆ:
Oczywiście bez podklas :)
EDYTOWAĆ:
Równie dobrze mogę opublikować mój problem na wypadek, gdyby ktoś miał lepszy pomysł:
Mam kilka przejść CCTransitions w COCOS2D i chcę być powiadamiany, kiedy przejście się skończy. Rzecz w tym, że jak tylko przejście się zakończy, -(void)finish; wywoływana jest metoda (która jest częścią struktury klasy CCTransition)
Naprawdę chciałbym uniknąć podklasowania klasy CCTransition i zastąpić metodę finish, aby wykonać moją logikę po zakończeniu przejścia :)
EDYTOWAĆ:
-(void)onEnterTransitionDidFinish; ... Nie mogę uwierzyć, że istniało coś tak niesamowitego i nie natknąłem się na to podczas wyszukiwania......
Co oznacza, że zamiast podklasy CCTransition nadpisać tę metodę w mojej podklasie CCNode :D!
3 odpowiedzi
To, co masz w Javie, to anonimowa podklasa. Nie jest to możliwe w Objective-C (no cóż, w pewnym sensie jest, ale musiałbyś zrobić trochę skomplikowanych skrzywień z biblioteką uruchomieniową Obj-C).
Ale Objective-C od iOS 4 lub OS X 10.6 ma „bloki”, do czego służy składnia ^{}
. To jest koncepcja Objective-C dotycząca zamknięcia. Nie pomoże to bezpośrednio, jeśli wywoływane interfejsy API nie obsługują wywołań zwrotnych bloków, ale możesz być w stanie utworzyć klasy otoki, które do obsługi wywołań zwrotnych używają bloków zamiast podklas metod.
Istnieje wiele zasobów do nauki o blokach w Cel C.
Nadal nie będzie bardzo czysto, ale zakładając, że chcesz skoncentrować brzydotę, możesz zrobić coś takiego (niesprawdzone):
Method methodToReplace =
[targetClass instanceMethodSignatureForSelector:@selector(methodToReplace)];
IMP implementationToSet =
[someProxyClass instanceMethodForSelector:@selector(implementationYouWant)];
method_setImplementation(methodToReplace, implementationToSet);
Odpowiednia dokumentacja referencyjna to Objective-C Runtime Reference oraz , opcjonalnie Informacje o klasie NSObject (ponieważ sprawia, że kilka rzeczy jest nieco ładniejszych, chociaż np. możesz użyć class_getInstanceMethod
ze środowiska wykonawczego zamiast instanceMethodSigntureForSelector:
).
Pamiętaj, że nie będziesz mieć możliwości wywołania oryginalnej implementacji, jeśli użyjesz dokładnie tego przepisu. method_setImplementation zwraca starą implementację, zazwyczaj rozsądnie jest dodać ją do klasy pod zupełnie nowym selektorem i wywołać ją w zamian.
Dla porównania, miałem uzasadniony powód, aby zrobić tego rodzaju rzeczy tylko raz: kiedy zaimplementowaliśmy obsługę drukowania w aplikacji na iOS, z którą musiała być kompatybilna zarówno z OS 3.2, jak i 4.0. Musisz podklasować konkretną klasę, ale klasa nie jest dostępna w 3.2. Musisz więc w pewnym sensie tworzyć podklasy w czasie wykonywania (chociaż koncepcyjnie lepszym sposobem byłoby użycie normalnej podklasy, umieszczenie jej w ramach i słabe łącze, ale warunki Apple SDK dla iOS zezwalają tylko na statyczne biblioteki, więc...).
+load
działa jeszcze przed main()
. Ale według Mike'a Asha, metoda +load
kategorii jest wykonywana wraz z implementacją głównej klasy, więc możesz być w stanie umieścić hacki w kategorii na +[NSObject load]
...
Zgodnie z sugestią Daniela możesz zaimplementować metodę w kategorii NSObject
formularza
[anObject overrideMethod:@selector(foo:)
byBlock:^(id self,id super,id originalArg){
...
}];
Co musisz zrobić, to
objc_allocateClassPair
przeciwko własnej klasieself
, aby utworzyć nową klasę tymczasową- Zmień blok we wskaźnik funkcji, używając np. to lub to
method_setImplementation
, aby ustawić nową implementację na klasę tymczasową- użyj
object_setClass
doself
, aby ustawić klasę na nową klasę tymczasową - Nie wymyśliłem, jak dodać
super
do bloku :p
Uważa się, że tak właśnie robi KVO przez Apple, zob. ta dyskusja.
Przeczytaj Informacje o środowisku wykonawczym.
super
, ale prawdopodobnie mógłbyś napisać metodę lub funkcję, która wywołuje implementację metody rodzica, taką jak -(id)callSuperMethod:(SEL)selector withObject:(id)arg1 ...
.
[[self super] doSomething:...]
.
Podobne pytania
Powiązane pytania
Nowe pytania
objective-c
Tego znacznika należy używać tylko w przypadku pytań dotyczących funkcji Objective-C lub zależnych od kodu w języku. Tagi [cocoa] i [cocoa-touch] powinny być używane, aby zapytać o ramy lub klasy Apple. Użyj powiązanych tagów [ios], [macos], [apple-watch] i [tvos] w przypadku problemów specyficznych dla tych platform.