Widziałem wiele strategii deklarowania metod półprywatnych w Objective-C , ale wydaje się, że nie ma sposobu na stworzenie metody prawdziwie prywatnej. Akceptuje to. Ale dlaczego tak jest? Każde wyjaśnienie, które zasadniczo mówię: „nie możesz tego zrobić, ale tutaj jest bliskie przybliżenie”.
Istnieje wiele słów kluczowych stosuje się do ivars
(członków), które kontrolują ich zakres, na przykład @private
, @public
, @protected
. Dlaczego nie można tego zrobić również w przypadku metod? Wygląda na to, że środowisko wykonawcze powinno być w stanie obsłużyć. Czy brakuje mi jakiejś podstawowej filozofii? Czy to celowe?
objective-c
objective-c-runtime
Rob Jones
źródło
źródło
Odpowiedzi:
Odpowiedź jest ... cóż ... prosta. A właściwie prostota i konsekwencja.
Cel-C jest czysto dynamiczny w momencie wysyłania metody. W szczególności, każda wysyłka metody przechodzi przez dokładnie ten sam dynamiczny punkt rozwiązania metody, co każda inna wysyłka metody. W czasie wykonywania każda implementacja metody ma dokładnie taką samą ekspozycję, a wszystkie interfejsy API dostarczane przez środowisko wykonawcze Objective-C, które współpracują z metodami i selektorami, działają tak samo we wszystkich metodach.
Jak wielu odpowiedziało (zarówno tutaj, jak i w innych pytaniach), obsługiwane są prywatne metody kompilacji; jeśli klasa nie deklaruje metody w swoim publicznie dostępnym interfejsie, to ta metoda równie dobrze może nie istnieć, jeśli chodzi o Twój kod. Innymi słowy, możesz osiągnąć wszystkie różne kombinacje widoczności pożądane w czasie kompilacji, odpowiednio organizując projekt.
Duplikowanie tej samej funkcjonalności w środowisku wykonawczym nie przynosi większych korzyści. Dodałoby to ogromną złożoność i narzut. I nawet przy całej tej złożoności, nadal nie przeszkodziłoby to wszystkim, z wyjątkiem najbardziej przypadkowego programisty, w wykonywaniu twoich rzekomo „prywatnych” metod.
Jednak takie postępowanie podważyłoby czystą dynamiczną naturę języka. Nie każda wysyłka metodą będzie już przechodzić przez identyczny mechanizm. Zamiast tego zostałbyś pozostawiony w sytuacji, w której większość metod zachowuje się w jeden sposób, a kilka jest po prostu innych.
Wykracza to poza środowisko wykonawcze, ponieważ w kakao jest wiele mechanizmów opartych na konsekwentnej dynamice Objective-C. Na przykład zarówno kodowanie wartości klucza, jak i obserwacja wartości klucza musiałyby zostać bardzo mocno zmodyfikowane, aby obsługiwały metody prywatne - najprawdopodobniej poprzez utworzenie luki, którą można wykorzystać - albo metody prywatne byłyby niekompatybilne.
źródło
Środowisko wykonawcze mogłoby to obsługiwać, ale koszt byłby ogromny. Każdy wysyłany selektor musiałby zostać sprawdzony, czy jest prywatny czy publiczny dla tej klasy, albo każda klasa musiałaby zarządzać dwiema oddzielnymi tabelami wysyłania. To nie jest to samo dla przykładowych zmiennych, ponieważ ten poziom ochrony jest wykonywany w czasie kompilacji.
Ponadto środowisko wykonawcze musiałoby zweryfikować, czy nadawca prywatnej wiadomości jest tej samej klasy co odbiorca. Możesz także ominąć metody prywatne; jeśli użyta klasa
instanceMethodForSelector:
, mogłaby zwrócić wartość zwróconąIMP
dowolnej innej klasie, aby mogli bezpośrednio wywołać metodę prywatną.Metody prywatne nie mogą ominąć wysłania wiadomości. Rozważ następujący scenariusz:
Klasa
AllPublic
ma metodę wystąpienia publicznegodoSomething
Inna klasa
HasPrivate
ma również metodę wystąpienia prywatnego o nazwiedoSomething
Tworzysz tablicę zawierającą dowolną liczbę wystąpień obu
AllPublic
iHasPrivate
Masz następującą pętlę:
Jeśli uruchomiłeś tę pętlę od wewnątrz
AllPublic
, środowisko wykonawcze będzie musiało zatrzymać wysyłaniedoSomething
naHasPrivate
instancje, jednak ta pętla byłaby użyteczna, gdyby znajdowała się wewnątrzHasPrivate
klasy.źródło
Opublikowane dotychczas odpowiedzi dobrze sobie radzą z odpowiedzią na pytanie z filozoficznej perspektywy, więc zamierzam postawić bardziej pragmatyczny powód: co zyskałoby się dzięki zmianie semantyki języka? Dość łatwo jest skutecznie „ukryć” prywatne metody. Na przykład wyobraź sobie, że masz klasę zadeklarowaną w pliku nagłówkowym, na przykład:
Jeśli potrzebujesz "prywatnych" metod, możesz również umieścić to w pliku implementacji:
Oczywiście, to nie jest zupełnie tak samo jak C ++ / Java metod prywatnych, ale to faktycznie na tyle blisko, więc po co zmieniać semantykę języka, jak również kompilatora, czas pracy, etc., aby dodać funkcję, która już emulowane w dopuszczalnym sposób? Jak zauważono w innych odpowiedziach, semantyka przekazywania wiadomości - i jej zależność od refleksji w czasie wykonywania - sprawiłaby, że obsługa wiadomości „prywatnych” byłaby nietrywialna.
źródło
Najłatwiejszym rozwiązaniem jest po prostu zadeklarowanie statycznych funkcji C w klasach Objective-C. Mają one tylko zasięg plikowy zgodnie z regułami C dla słowa kluczowego static i dlatego mogą być używane tylko przez metody w tej klasie.
Bez zamieszania.
źródło
Tak, można to zrobić bez wpływu na środowisko uruchomieniowe, wykorzystując technikę już stosowaną przez kompilatory do obsługi C ++: mangling nazw.
Nie zostało to zrobione, ponieważ nie ustalono, że rozwiązałoby to znaczną trudność w przestrzeni problemowej kodowania, którą inne techniki (np. Prefiksowanie lub podkreślanie) są w stanie obejść w wystarczającym stopniu. IOW, potrzebujesz więcej bólu, aby przezwyciężyć zakorzenione nawyki.
Mógłbyś wnieść łaty do clang lub gcc, które dodają prywatne metody do składni i wygenerują zniekształcone nazwy, które sam rozpoznał podczas kompilacji (i natychmiast zapomniał). Wtedy inni członkowie społeczności Objective-C byliby w stanie określić, czy było to rzeczywiście warte zachodu, czy nie. W ten sposób prawdopodobnie będzie szybszy niż próba przekonania programistów.
źródło
Zasadniczo ma to związek z formą wywołań metod przekazywania komunikatów Objective-C. Dowolną wiadomość można wysłać do dowolnego obiektu, a obiekt sam wybiera sposób odpowiedzi na wiadomość. Zwykle zareaguje, wykonując metodę nazwaną po wiadomości, ale może również odpowiedzieć na wiele innych sposobów. Nie oznacza to, że metody prywatne są całkowicie niemożliwe - Ruby robi to z podobnym systemem przekazywania wiadomości - ale czyni je nieco niezręcznymi.
Nawet implementacja prywatnych metod w Ruby jest nieco myląca dla ludzi z powodu dziwności (możesz wysłać obiektowi dowolną wiadomość, z wyjątkiem tych z tej listy !). Zasadniczo Ruby sprawia, że działa, zabraniając wywoływania metod prywatnych z jawnym odbiornikiem. W Objective-C wymagałoby to jeszcze więcej pracy, ponieważ Objective-C nie ma takiej opcji.
źródło
Jest to problem ze środowiskiem wykonawczym Objective-C. Podczas gdy C / C ++ kompiluje się do nieczytelnego kodu maszynowego, Objective-C nadal zachowuje pewne czytelne dla człowieka atrybuty, takie jak nazwy metod jako ciągi . To daje Objective-C możliwość wykonywania funkcji odblaskowych .
EDYCJA: Bycie językiem refleksyjnym bez ścisłych prywatnych metod sprawia, że Objective-C jest bardziej „pythonowe”, ponieważ ufasz innym ludziom, którzy używają Twojego kodu, zamiast ograniczać metody, które mogą wywoływać. Stosowanie konwencji nazewnictwa, takich jak podwójne podkreślenia, ma na celu ukrycie kodu przed zwykłym programistą klienta, ale nie powstrzyma programistów przed bardziej poważną pracą.
źródło
Istnieją dwie odpowiedzi w zależności od interpretacji pytania.
Pierwsza polega na ukryciu implementacji metody w interfejsie. Jest to używane, zazwyczaj z kategorią bez nazwy (np
@interface Foo()
.). Pozwala to obiektowi na wysyłanie tych wiadomości, ale nie innych - chociaż nadal można je zastąpić przypadkowo (lub w inny sposób).Druga odpowiedź, przy założeniu, że chodzi o wydajność i inlining, jest możliwa, ale zamiast tego jako lokalna funkcja C. Jeśli chciałeś „prywatny Foo (
NSString *arg
)” metoda, to zrobivoid MyClass_foo(MyClass *self, NSString *arg)
i wywołać ją jako funkcję C podobnegoMyClass_foo(self,arg)
. Składnia jest inna, ale działa z rozsądnym rodzajem charakterystyk wydajności prywatnych metod C ++.Chociaż to odpowiada na pytanie, powinienem zauważyć, że kategoria bez nazwy jest zdecydowanie bardziej powszechnym sposobem realizacji celu C.
źródło
Objective-C nie obsługuje metod prywatnych, ponieważ ich nie potrzebuje.
W C ++ każda metoda musi być widoczna w deklaracji klasy. Nie możesz mieć metod, których ktoś zawierający plik nagłówkowy nie może zobaczyć. Więc jeśli chcesz, aby metody, których kod poza twoją implementacją nie były używane, nie masz wyboru, kompilator musi dać ci jakieś narzędzie, abyś mógł powiedzieć, że metody nie wolno używać, to jest słowo kluczowe „private”.
W Objective-C możesz mieć metody, których nie ma w pliku nagłówkowym. Więc bardzo łatwo osiągniesz ten sam cel, nie dodając metody do pliku nagłówkowego. Nie ma potrzeby stosowania prywatnych metod. Objective-C ma również tę zaletę, że nie musisz ponownie kompilować każdego użytkownika klasy, ponieważ zmieniłeś metody prywatne.
Na przykład zmienne, które musiałeś zadeklarować w pliku nagłówkowym (już nie), dostępne są @private, @public i @protected.
źródło
Brakuje tu odpowiedzi: ponieważ metody prywatne to zły pomysł z punktu widzenia ewolucji. Może wydawać się dobrym pomysłem ustawienie metody jako prywatnej podczas jej pisania, ale jest to forma wczesnego wiązania. Kontekst może się zmienić, a późniejszy użytkownik może chcieć użyć innej implementacji. Trochę prowokacyjne: „Zwinni programiści nie używają metod prywatnych”
W pewnym sensie, podobnie jak Smalltalk, Objective-C jest dla dorosłych programistów. Cenimy wiedzę o tym, jaki powinien być interfejs, i bierzemy odpowiedzialność za radzenie sobie z konsekwencjami, jeśli zajdzie potrzeba zmiany implementacji. Więc tak, to filozofia, a nie implementacja.
źródło