2011-04-28 9 views
13

Przejrzałem kilka postów na ten temat. Może nie natknąłem się na "jedynego" i ktoś wskaże mi w tym kierunku. Pytanie jest proste i prawdopodobnie ma prostą odpowiedź.Jak zadeklarować zmienne i metody instancji niewidoczne lub użyteczne poza instancją klasy?

Jeśli masz dwa znaki iv, na przykład "public_ivar" i "private_ivar", gdzie/jak powinieneś je zadeklarować, aby to, co publiczne, było publiczne, a to, co prywatne, nie zostało w żaden sposób ujawnione nikomu patrzącemu na nagłówek plik?

To samo pytanie w przypadku "public_method" i "private_method".

Lubię czyste pliki nagłówkowe (w innych językach), które tylko eksponują metody i znaki iv, które chcę zobaczyć. Powinieneś być w stanie opublikować swój plik nagłówkowy i nie narażać się na niebezpieczeństwo dostępu do czegoś, czego nie powinien. Jak to zrobić w celu-C.

Na przykład, powiedzmy, że zdecyduję, że muszę użyć ivar do śledzenia niektórych danych, licznika lub czegoś podobnego, pomiędzy różnymi metodami klasowymi, które wszystkie wymagają dostępu do tych informacji. Jeśli tenvar jest zadeklarowany w nagłówku w nagłówku @interface, jego istnienie jest publicznie anonsowane i jest użyteczne dla każdego, kto tworzy instancję klasy. Idealnym scenariuszem byłoby to, że ten ivar nie byłby w ogóle widoczny poza implementacją klasy.

Odpowiedz

17

Możesz zadeklarować zmienne instancji lub zadeklarowane właściwości w rozszerzeniu klasy. Ponieważ rozszerzenie klasy jest zadeklarowane w pliku implementacji (tj. Nie jest plikiem nagłówkowym), nie będą one widoczne dla kogoś kontrolującego plik nagłówkowy. Na przykład, w pliku nagłówka:

@interface SomeClass : NSObject 
@end 

iw pliku realizacji:

@interface SomeClass() 
@property (nonatomic, assign) int privateInt; 
@end 

@implementation SomeClass 

@synthesize privateInt; 
… 
@end 

lub

@interface SomeClass() { 
    int privateInt; 
} 
@end 

@implementation SomeClass 
… 
@end 

pamiętać, że nie ma nic wykluczając dostęp do prywatnych/klasa zmiennych instancji przedłużenie (lub metody uzyskiwania właściwości zadeklarowanych w rozszerzeniu klasy) podczas wykonywania. Pisałem dość szczegółowy post o tym w odpowiedzi na inne pytanie na przepełnienie stosu: Does a private @property create an @private instance variable?

Edit: zmienne instancji w rozszerzeniach klasy zostały przedstawione w sesji WWDC 2010 144.

Edit: "Za pomocą kompilatora Clang/LLVM 2.0 można również zadeklarować właściwości i zmienne instancji w rozszerzeniu klasy."

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1

+0

OK, przyjrzę to. Robię trochę pracy z Genetycznymi Algorytmami i Sieciami Neuronowymi. Klasy kończą się stosami zmiennych, które są potrzebne wewnętrznie. Bardzo niewiele z nich naprawdę potrzebuje widoczności na poziomie pliku nagłówkowego. Czy twój pierwszy przykład pliku implementacji dla iOS4 + (ponieważ nie deklarujesz int privateInt przed przedrostkiem @property)? –

+0

@Martin Nie jestem pewien, kiedy Objective-C 2.0, który pozwala na automatyczne tworzenie zmiennych instancji kopii zapasowej, został udostępniony systemowi iOS. –

+0

@Martin [Ta strona w witrynie firmy Apple] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html%23//apple_ref/doc/uid/ TP40008048-CH106-SW1) nie zawiera konkretnej wersji systemu iOS. –

2

Możesz użyć @private, aby określić, że ivars są prywatne. Jednak nie ma sposobu, aby uczynić metodę prywatną. Nawet jeśli metoda nie jest wymieniona w pliku nagłówkowym, jeśli ktoś zna nazwę i argumenty, może ją nazwać.

+0

Jak rozumiem, @private tak naprawdę nie robi niczego, jeśli posiadasz deklaracje @property (ustawiające i pobierające). Nie chcę nawet, aby funkcja ivar lub funkcja prywatnego członka była w nagłówku. Przy takim założeniu, że nikt o nich nie wie, powinni pozostać niewidzialni (tylko starać się uczciwie uczciwych ludzi, jeśli chcesz kopać, możesz odkryć wszystko). Po prostu uważam, że "brudne" jest to, że wszystkie te rzeczy w nagłówku są zupełnie nieistotne dla innych części aplikacji. –

+1

@Martin: Właściwość nie jest ivar. Jeśli chodzi o ukrywanie znaków iv w nagłówku, mogę wymyślić dwie opcje: Możesz mieć tylko ivar będący wskaźnikiem do struktury, która jest zadeklarowana gdzie indziej, lub możesz mieć wszystkie instancje faktycznie będące prywatnymi podklasami (zgodnie z tym, co robi Apple z klastrami klasy). – Anomie

+0

Winny lenistwa z językiem. Rozumiem, że @property tworzy po prostu podstawowy kod ustawiający i pobierający. Czy robi cokolwiek innego? –

4

Zastosowanie class extensions dodać do klasy w pliku implementacji. Rozszerzenie klasy to w zasadzie kategoria bez nazwy z kilkoma bonusami: właściwości zadeklarowane w niej można zsyntetyzować, a wszystko, co w niej zadeklarowane, musi znajdować się w głównej implementacji, aby kompilator mógł sprawdzić, czy nie pominął implementacji. Przed wdrożeniem musisz umieścić rozszerzenie klasy. Nie można dodawać zmiennych instancji bezpośrednio w rozszerzeniu klasy, ale można dodawać właściwości.Podczas syntezowania akcesorów dla właściwości, które nie mają odpowiednich zmiennych instancji, nowe środowisko wykonawcze (os x 10.5 i nowsze oraz wszystkie wersje systemu iOS, jak sądzę) automatycznie utworzy zmienne instancji. Oznacza to, że nie możesz tworzyć własnych akcesorów, chyba że umieścisz zmienną instancji w swoim nagłówku. Prywatne metody mogą być dodawane do rozszerzenia klasy bez ograniczeń, ale jak zauważył Anomie, technicznie możliwe jest ich użycie, jeśli wiesz, jak się nazywa i zrzutu klasy, nic nie jest bezpieczne.

Przykład użycia z rozszerzeniem klasy:

@interface MyClass() 
@property (retain) id privateIvar; 
@property (readwrite) id readonlyProperty; // bonus! class extensions can be used to make a property that is publicly readonly and privately readwrite 
- (void)privateMethod; 
@end 
@implementation MyClass 
@synthesize privateIvar; // the runtime will create the actual ivar, and we just access it through the property 
- (void)privateMethod { 
    ... 
} 
... 

Innym sposobem tworzenia „zmienne instancji” bez wprowadzenia ich w nagłówku lub stosując właściwość jest użycie associative references, która dodać dane do obiektu w czasie wykonywania. Nie są one technicznie takie same jak zmienne instancji, a ich składnia jest bardziej złożona. Ponieważ wymagają one również nowego środowiska wykonawczego, istnieją tylko dwa powody, dla których naprawdę chciałbyś ich użyć: chcesz dodać zmienną instancji w kategorii (poza zakresem tego pytania) lub potrzebujesz jej naprawdę naprawdę naprawdę prywatny. Odwołanie asocjacyjne nie tworzy żadnych metod ani nie dodaje definicji klasy do skompilowanego kodu, więc jeśli nie tworzy się dla nich wrapperów, nie można dowiedzieć się o nich bez pytania obiektu po dodaniu danych. Zobacz dolną stronę, którą podłączyłem, aby zobaczyć pełny przykład użycia.

+0

Więc ... jeśli potrzebujesz dostosowanego setera lub gettera dla "ukrytego" ivar'a, to nie możesz go napisać bez narażania ivar w nagłówku? –

+0

@Martin: Jak powiedział Bavarious, jak omówiono w komentarzach, ivars są teraz obsługiwane w rozszerzeniach klas, więc możesz je zadeklarować zamiast nagłówka. Można również użyć odwołań asocjacyjnych i pisać wokół nich opakowania jako akcesoria. – ughoavgfhw

Powiązane problemy