Właśnie zacząłem programować Objective-C i mając doświadczenie w Javie, zastanawiam się, jak ludzie piszący programy Objective-C radzą sobie z metodami prywatnymi.
Rozumiem, że może istnieć kilka konwencji i przyzwyczajeń, i myślę o tym pytaniu jako agregat najlepszych technik, z których ludzie korzystają w kontaktach z prywatnymi metodami w Objective-C.
Podaj argument za podejściem podczas jego publikowania. Dlaczego to jest dobre? Jakie wady ma (o których wiesz) i jak sobie z nimi radzisz?
Co do moich dotychczasowych ustaleń.
Możliwe jest użycie kategorii [np. MyClass (Private)] zdefiniowanych w pliku MyClass.m do grupowania metod prywatnych.
Podejście to ma 2 problemy:
- Xcode (i kompilator?) Nie sprawdza, czy zdefiniujesz wszystkie metody w kategorii prywatnej w odpowiednim bloku @implementation
- Musisz umieścić @interface deklarujący swoją prywatną kategorię na początku pliku MyClass.m, w przeciwnym razie Xcode narzeka na komunikat typu „ja może nie odpowiedzieć na wiadomość„ privateFoo ”.
Pierwszy problem można obejść z pustą kategorią [np. MyClass ()].
Drugi bardzo mnie niepokoi. Chciałbym, aby prywatne metody zostały zaimplementowane (i zdefiniowane) na końcu pliku; Nie wiem czy to możliwe.
źródło
Odpowiedzi:
Jak już powiedzieli inni, nie ma czegoś takiego jak prywatna metoda w Objective-C. Jednak począwszy od Objective-C 2.0 (czyli Mac OS X Leopard, iPhone OS 2.0 i nowsze) możesz utworzyć kategorię o pustej nazwie (tj.
@interface MyClass ()
) O nazwie Class Extension . Unikalne w rozszerzeniu klasy jest to, że implementacje metod muszą iść tak samo@implementation MyClass
jak metody publiczne. Więc układam moje klasy w ten sposób:W pliku .h:
I w pliku .m:
Myślę, że największą zaletą tego podejścia jest to, że pozwala on pogrupować implementacje metod według funkcjonalności, a nie (czasem arbitralnego) publicznego / prywatnego rozróżnienia.
źródło
if (bSizeDifference && [self isSizeDifferenceSignificant:fWidthCombined])...
zaczął się mętnieć, dopóki nie zagnieździłam takiego wywołania: wtedy fWidthCombined zawsze pojawiał się jako 0.W Objective-C nie ma tak naprawdę „prywatnej metody”, jeśli środowisko wykonawcze może ustalić, która implementacja go wykorzysta. Ale to nie znaczy, że nie ma metod, które nie są częścią udokumentowanego interfejsu. W przypadku tych metod uważam, że kategoria jest w porządku. Zamiast umieszczać
@interface
na początku pliku .m, jak w punkcie 2, umieściłem go we własnym pliku .h. Konwencja, którą stosuję (i widziałem gdzie indziej, myślę, że jest to konwencja Apple, ponieważ Xcode zapewnia teraz automatyczne wsparcie dla niej), polega na nazwaniu takiego pliku po klasie i kategorii za pomocą + oddzielającego go, więc@interface GLObject (PrivateMethods)
można go znaleźć wGLObject+PrivateMethods.h
. Powodem udostępnienia pliku nagłówkowego jest to, że możesz go zaimportować do swoich klas testów jednostkowych :-).Nawiasem mówiąc, jeśli chodzi o wdrażanie / definiowanie metod pod koniec pliku .m, możesz to zrobić za pomocą kategorii, implementując kategorię na dole pliku .m:
lub z rozszerzeniem klasy (rzecz, którą nazywacie „pustą kategorią”), wystarczy zdefiniować te metody na końcu. Metody Objective-C można definiować i stosować w dowolnej kolejności w implementacji, więc nic nie stoi na przeszkodzie, aby umieścić metody „prywatne” na końcu pliku.
Nawet z rozszerzeniami klas często tworzę osobny nagłówek (
GLObject+Extension.h
), aby w razie potrzeby móc korzystać z tych metod, naśladując widoczność „przyjaciela” lub „chronionej”.Ponieważ ta odpowiedź została napisana pierwotnie, kompilator clang zaczął wykonywać dwa przejścia dla metod Objective-C. Oznacza to, że możesz uniknąć całkowitego zadeklarowania swoich „prywatnych” metod i czy są one powyżej czy poniżej strony wywołującej, zostaną one znalezione przez kompilator.
źródło
Chociaż nie jestem ekspertem od Objective-C, osobiście po prostu definiuję metodę w implementacji mojej klasy. To prawda, że należy go zdefiniować przed (powyżej) dowolnymi metodami go wywołującymi, ale zdecydowanie zajmuje to najmniej pracy.
źródło
Zdefiniowanie prywatnych metod w
@implementation
bloku jest idealne do większości celów. Clang zobaczy je w@implementation
, niezależnie od kolejności deklaracji. Nie ma potrzeby deklarowania ich w kontynuacji klasy (aka rozszerzenie klasy) lub kategorii nazwanej.W niektórych przypadkach będziesz musiał zadeklarować metodę w kontynuacji klasy (np. Jeśli używasz selektora między kontynuacją klasy a
@implementation
).static
funkcje są bardzo dobre dla szczególnie wrażliwych lub krytycznych pod względem szybkości prywatnych metod.Konwencja nazywania prefiksów może pomóc ci uniknąć przypadkowego zastąpienia metod prywatnych (uważam, że nazwa klasy jest bezpieczna dla prefiksu).
Nazwane kategorie (np.
@interface MONObject (PrivateStuff)
) Nie są szczególnie dobrym pomysłem ze względu na potencjalne kolizje nazw podczas ładowania. Są one naprawdę przydatne tylko w przypadku metod przyjacielskich lub chronionych (które bardzo rzadko są dobrym wyborem). Aby upewnić się, że jesteś ostrzegany przed niekompletnymi implementacjami kategorii, powinieneś to zaimplementować:Oto mała ściągawka z adnotacjami:
MONObject.h
MONObject.m
Inne podejście, które może nie być oczywiste: typ C ++ może być zarówno bardzo szybki, jak i zapewniać znacznie wyższy stopień kontroli, minimalizując jednocześnie liczbę eksportowanych i ładowanych metod objc.
źródło
Możesz spróbować zdefiniować funkcję statyczną poniżej lub powyżej implementacji, która przenosi wskaźnik do instancji. Będzie mógł uzyskać dostęp do dowolnej zmiennej Twojego wystąpienia.
źródło
Możesz użyć bloków?
Wiem, że to stare pytanie, ale jedno z pierwszych, jakie znalazłem, kiedy szukałem odpowiedzi na to właśnie pytanie. Nigdzie indziej nie widziałem tego rozwiązania, więc daj mi znać, jeśli jest w tym coś głupiego.
źródło
static
). Ale eksperymentowałem z przypisywaniem bloków prywatnym ivarom (z metody init) - w pewnym sensie w stylu JavaScript - który pozwala również na dostęp do prywatnych ivars, co jest niemożliwe z funkcji statycznych. Nie jestem pewien, który wolę.wszystkie obiekty w Celu C są zgodne z protokołem NSObject, który utrzymuje performSelector: metodęWcześniej szukałem też sposobu na stworzenie „pomocniczych lub prywatnych” metod, których nie potrzebowałem ujawniać na poziomie publicznym. Jeśli chcesz stworzyć prywatną metodę bez narzutów i nie musisz jej definiować w pliku nagłówkowym, spróbuj tego ...
zdefiniuj swoją metodę z podobną sygnaturą jak poniższy kod ...
wtedy, gdy musisz odwołać się do metody, po prostu wywołaj ją jako selektor ...
ten wiersz kodu wywoła metodę, którą utworzyłeś i nie będzie irytujący ostrzeżenie o braku zdefiniowania jej w pliku nagłówkowym.
źródło
Jeśli chcesz uniknąć
@interface
bloku na górze, zawsze możesz umieścić prywatne deklaracje w innym pliku, coMyClassPrivate.h
nie jest idealne, ale nie zaśmieca implementacji.MyClass.h
MyClassPrivate.h
MyClass.m
źródło
Jeszcze jedna rzecz, o której tu nie wspominałem - Xcode obsługuje pliki .h z nazwą „_private” w nazwie. Załóżmy, że masz klasę MyClass - masz MyClass.m i MyClass.h, a teraz możesz także mieć MyClass_private.h. Xcode rozpozna to i umieści ją na liście „odpowiedników” w edytorze asystenta.
źródło
Nie ma sposobu na obejście problemu nr 2. Tak właśnie działa kompilator C (a zatem i kompilator Objective-C). Jeśli korzystasz z edytora XCode, wyskakujące okienko funkcji powinno ułatwić nawigację w blokach
@interface
i@implementation
w pliku.źródło
Zaletą nieobecności metod prywatnych. Możesz przenieść logikę, którą chciałeś ukryć, do osobnej klasy i użyć jej jako delegata. W takim przypadku możesz oznaczyć obiekt delegowany jako prywatny i nie będzie on widoczny z zewnątrz. Przeniesienie logiki do osobnej klasy (może kilku) usprawnia projektowanie twojego projektu. Ponieważ twoje klasy stają się prostsze, a twoje metody są pogrupowane w klasy o odpowiednich nazwach.
źródło
Jak powiedzieli inni, zdefiniowanie prywatnych metod w
@implementation
bloku jest w większości przypadków OK.Na temat organizacji kodu - lubię trzymać je razem,
pragma mark private
aby ułatwić nawigację w Xcodeźródło