Zastępowanie metod przy użyciu kategorii w Objective-C

87

Czy mogę użyć kategorii klasy, aby przesłonić metodę, która została już zaimplementowana przy użyciu kategorii? Lubię to:

1) Oryginalna metoda

-(BOOL) method {
  return true;
}

2) Metoda nadpisana

-(BOOL) method {
  NSLog(@"error?"); 
  return true; 
}

Czy to zadziała, czy jest to nielegalne?

retix
źródło

Odpowiedzi:

146

Z dokumentacji Apple :

Chociaż język Objective-C obecnie pozwala na użycie kategorii do przesłonięcia metod dziedziczonych przez klasę, a nawet metod zadeklarowanych w interfejsie klasy, zdecydowanie odradza się tego . Kategoria nie zastępuje podklasy. Istnieje kilka istotnych niedociągnięć w używaniu kategorii do zastępowania metod:

  • Gdy kategoria zastępuje dziedziczoną metodę, metoda w kategorii może, jak zwykle, wywołać odziedziczoną implementację za pośrednictwem komunikatu do super. Jednakże, jeśli kategoria nadpisuje metodę, która istnieje w klasie kategorii, nie istnieje żaden sposób, aby wywołać oryginalną realizację .

  • Kategoria nie może niezawodnie przesłonić metod zadeklarowanych w innej kategorii tej samej klasy.

    Ta kwestia ma szczególne znaczenie, ponieważ wiele klas Cocoa jest implementowanych przy użyciu kategorii. Metoda zdefiniowana w ramach, którą próbujesz zastąpić, mogła sama zostać zaimplementowana w kategorii, dlatego nie zdefiniowano, która implementacja ma pierwszeństwo.

  • Sama obecność niektórych metod kategorii może powodować zmiany zachowania we wszystkich frameworkach. Na przykład, jeśli zastąpisz windowWillClose:metodę delegata w kategorii w NSObject, wszyscy delegaci okna w programie odpowiedzą przy użyciu metody category; zachowanie wszystkich wystąpień NSWindow może ulec zmianie. Kategorie dodane do klasy frameworka mogą powodować tajemnicze zmiany w zachowaniu i prowadzić do awarii.

Benoît
źródło
Dziękuję, ale już to wiem. Zastanawiam się tylko, czy moja sprawa jest legalna, czy nie. Moja sprawa różni się nieco od dokumentów. :)
retix
Dlaczego jest inaczej? Dokument mówi, że jest to legalne, JEŚLI oryginalna metoda nie znajduje się w kategorii, ale jest zdecydowanie odradzana. Wtedy możesz to zrobić ...
Benoît
1
Dziękuję za radę. Jestem biedny w tym języku. Otrzymałem od ciebie nowe informacje.
retix
1
Czy poprawne jest zastąpienie metody Category zadeklarowanej i zaimplementowanej w kategorii superklasy?
BergP,
2
Link jest uszkodzony, czy to jest nowa wersja? developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…
RndmTsk
18

Możesz to zrobić, dostosowując podejście Class Cluster lub używając techniki zawijania metod.

W przeciwnym razie zachowanie dwóch lub więcej metod skategoryzowanych jest niezdefiniowane

Martin Babacaev
źródło
9

Stary link do dokumentacji jest martwy; najlepszy zamiennik, jaki udało mi się znaleźć, był tutaj: Apple Docs :

Unikaj kolizji nazw metod kategorii

Ponieważ metody zadeklarowane w kategorii są dodawane do istniejącej klasy, należy bardzo uważać na nazwy metod.

Jeśli nazwa metody zadeklarowanej w kategorii jest taka sama, jak metoda w oryginalnej klasie lub metoda w innej kategorii w tej samej klasie (lub nawet w nadklasie), zachowanie jest niezdefiniowane co do tego, która implementacja metody jest używana w runtime. Jest to mniej prawdopodobne, jeśli używasz kategorii z własnymi klasami, ale może powodować problemy podczas używania kategorii do dodawania metod do standardowych klas Cocoa lub Cocoa Touch.

To Apple używa lżejszego dotyku, ale główny punkt jest ten sam: zapraszasz do katastrofy, ponieważ nieprzewidywalne zachowanie jest ciche.

AmitaiB
źródło
2

Należy zauważyć, że kategoria może być również używana do przesłonięcia istniejących metod w klasie bazowej (np. Metoda napędu klasy Car), ale nigdy nie należy tego robić. Problem w tym, że kategorie to płaska struktura organizacyjna. Jeśli zastąpisz istniejącą metodę w Car + Maintenance.m, a następnie zdecydujesz, że chcesz ponownie zmienić jej zachowanie z inną kategorią, nie ma sposobu, aby Objective-C wiedział, której implementacji użyć. W takiej sytuacji podklasy są prawie zawsze lepszą opcją.

Z tego samouczka http://rypress.com/tutorials/objective-c/categories

Vinuta
źródło