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!

5
Mazyod 2 czerwiec 2011, 15:51
1
Czy chcesz zastąpić metodę w klasie, czy tylko w jednym obiekcie (instancji klasy)?
 – 
sergio
2 czerwiec 2011, 15:54
Odpowiem, aby użyć podklasy. Nie znam innych sposobów...
 – 
Chanok
2 czerwiec 2011, 15:59
Jest to bardzo możliwe i wygodne w Javie.. Myślałem, że Object-C jest jeszcze bardziej wszechstronny?
 – 
Mazyod
2 czerwiec 2011, 16:01
2
Można to zrobić w czasie wykonywania, możesz nawet skompilować metodę z ciągu, jeśli chcesz, ale dlaczego nie użyć podklasy? Do tego właśnie służy podklasa.
 – 
hooleyhoop
2 czerwiec 2011, 16:06
Skończę na podklasie około 10 klas. CCTransitionFadeIn, CCTransitionSlideIn, ...itd. I każdy ma swoją własną logikę. Łatwość utrzymania/czytelność jest dla mnie bardzo ważnym wymogiem.
 – 
Mazyod
2 czerwiec 2011, 16:09

3 odpowiedzi

Najlepsza odpowiedź

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.

2
Abizern 2 czerwiec 2011, 16:21
Aaah, anonimowa klasa wewnętrzna.. Właśnie przypomniałeś mi stare dobre czasy z Javą :) ... Tak, to jest odpowiedź, której potrzebowałem "To, co masz w Javie, to anonimowa podklasa. Nie jest to możliwe w Objective-C " .. Dziękuję!
 – 
Mazyod
2 czerwiec 2011, 16:27

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...).

7
Tommy 2 czerwiec 2011, 16:19
To interesująca sytuacja, gdy potrzebujesz podklas tworzonych w czasie wykonywania. Zastanawiam się, czy nieco łatwiejszym sposobem byłoby dynamiczne tworzenie fikcyjnej nadklasy w czasie wykonywania na początku wykonywania programu, aby można było normalnie zdefiniować podklasę. Czy to w ogóle zadziała?
 – 
Daniel Dickison
2 czerwiec 2011, 16:29
Jestem na skraju mojego poziomu wiedzy tutaj, ale myślę, że potencjalny problem polegałby na tym, że metaklasa związana z moją podklasą zostałaby utworzona przez system podczas ładowania pliku binarnego. Ponieważ klasa nadrzędna by wtedy nie istniała, wyobrażam sobie, że otrzymam wyjątek i w ogóle nie uruchomię się.
 – 
Tommy
2 czerwiec 2011, 17:58
Wygląda na to, że masz rację: +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]...
 – 
Daniel Dickison
2 czerwiec 2011, 23:18
Wspomina, że ​​frameworki są ładowane jako pierwsze, a +load jest przypadkiem szczególnym (możesz mieć wiele +obciążeń dla klasy i wszystkie są wywoływane), wydaje mi się, że pytanie brzmi, czy kategoria +load zostanie wywołana po załadowaniu frameworków mimo że NSObject jest niezbędny do załadowania frameworków. Jeśli tak, to masz rację — schludniejszym i lepszym rozwiązaniem, które prawie na pewno działałoby, byłoby dodanie fikcyjnej klasy nadrzędnej do środowiska wykonawczego i zaimplementowanie mojej podklasy drukowania dokładnie tak, jakbym celował tylko w 4.0. Jest mniej do wycięcia, gdy odrzucimy wsparcie 3.2, jeśli nic więcej.
 – 
Tommy
3 czerwiec 2011, 15:36

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

  1. objc_allocateClassPair przeciwko własnej klasie self, aby utworzyć nową klasę tymczasową
  2. Zmień blok we wskaźnik funkcji, używając np. to lub to
  3. method_setImplementation, aby ustawić nową implementację na klasę tymczasową
  4. użyj object_setClass do self, aby ustawić klasę na nową klasę tymczasową
  5. 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.

3
Community 23 maj 2017, 15:04
To byłoby bardzo fajne. Nie przychodzi mi do głowy żaden sposób dostarczenia 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 ....
 – 
Daniel Dickison
2 czerwiec 2011, 23:08
Cóż, myślę, że możesz napisać metodę trampoliny, która wysyła metodę do super, na przykład: [[self super] doSomething:...].
 – 
Yuji
3 czerwiec 2011, 00:32