Co oznacza „@private” w Objective-C?


Odpowiedzi:


186

To modyfikator widoczności - oznacza to, że zmienne instancji zadeklarowane jako @privatemogą być dostępne tylko dla instancji tej samej klasy . Członkowie prywatni nie mogą uzyskać dostępu do podklas ani innych klas.

Na przykład:

@interface MyClass : NSObject
{
    @private
    int someVar;  // Can only be accessed by instances of MyClass

    @public
    int aPublicVar;  // Can be accessed by any object
}
@end

Ponadto, aby wyjaśnić, metody są zawsze publiczne w Celu C. Istnieją jednak sposoby „ukrywania” deklaracji metod - więcej informacji można znaleźć w tym pytaniu .


Co ze zmiennymi instancji, które znajdują się w nawiasach klamrowych po @implementation? Czy zawsze są prywatne?
— John Henckel,

Wiem, że jest stary ... Ale to nie jest modyfikator widoczności. To modyfikator dostępu. Jest to ważniejsze rozróżnienie w C ++, ale jest to również rozróżnienie w Objective-C. Zmienna jest widoczna dla kompilatora. Kompilator po prostu nie pozwala ci na dostęp.
— gnasher729

161

Jak powiedział htw, jest to modyfikator widoczności. @privateoznacza, że ​​dostęp do ivar (zmienna instancji) można uzyskać wyłącznie bezpośrednio z instancji tej samej klasy. Może to jednak niewiele dla ciebie znaczyć, więc dam ci przykład. initDla uproszczenia wykorzystamy metody klas jako przykłady. Skomentuję w tekście, aby wskazać interesujące przedmioty.

@interface MyFirstClass : NSObject
{
    @public
    int publicNumber;

    @protected  // Protected is the default
    char protectedLetter;

    @private
    BOOL privateBool;
}
@end

@implementation MyFirstClass
- (id)init {
    if (self = [super init]) {
        publicNumber = 3;
        protectedLetter = 'Q';
        privateBool = NO;
    }
    return self;
}
@end

@interface MySecondClass : MyFirstClass  // Note the inheritance
{
    @private
    double secondClassCitizen;
}
@end

@implementation MySecondClass
- (id)init {
    if (self = [super init]) {
        // We can access publicNumber because it's public;
        // ANYONE can access it.
        publicNumber = 5;

        // We can access protectedLetter because it's protected
        // and it is declared by a superclass; @protected variables
        // are available to subclasses.
        protectedLetter = 'z';

        // We can't access privateBool because it's private;
        // only methods of the class that declared privateBool
        // can use it
        privateBool = NO;  // COMPILER ERROR HERE

        // We can access secondClassCitizen directly because we 
        // declared it; even though it's private, we can get it.
        secondClassCitizen = 5.2;  
    }
    return self;
}

@interface SomeOtherClass : NSObject
{
    MySecondClass *other;
}
@end

@implementation SomeOtherClass
- (id)init {
    if (self = [super init]) {
        other = [[MySecondClass alloc] init];

        // Neither MyFirstClass nor MySecondClass provided any 
        // accessor methods, so if we're going to access any ivars
        // we'll have to do it directly, like this:
        other->publicNumber = 42;

        // If we try to use direct access on any other ivars,
        // the compiler won't let us
        other->protectedLetter = 'M';     // COMPILER ERROR HERE
        other->privateBool = YES;         // COMPILER ERROR HERE
        other->secondClassCitizen = 1.2;  // COMPILER ERROR HERE
    }
    return self;
}

Aby odpowiedzieć na twoje pytanie, @private chroni ivars przed dostępem przez instancję dowolnej innej klasy. Zauważ, że dwa wystąpienia MyFirstClass mogą uzyskać bezpośredni dostęp do wszystkich swoich ivarów; zakłada się, że ponieważ programista ma pełną kontrolę nad tą klasą bezpośrednio, umiejętnie wykorzysta tę umiejętność.


20
Należy wspomnieć, że rzadkie jest używanie @public, @proteced i @private w Objective-C. Preferowanym podejściem jest zawsze korzystanie z akcesoriów.
— Georg Schölly

1
@Georg, ale jak wymusić użycie akcesoriów, chyba że oznaczysz swoje samochody z ograniczoną widocznością?
— Greg Maletic,

5
@Georg Schölly: Ponieważ xcode 4.x + automatycznie umieszcza @privateszablon dla obiektu, nie jest już tak rzadki.
— dawg

1
@Georg Myślę, że @prywatna, @protected może być używana w przypadkach, w których występuje dziedziczenie, ale nie korzystałem z niej osobiście :)
— chunkyguy

5
Należy zauważyć, że obecnie niewiele jest powodów, aby umieszczać zmienne instancji w nagłówku publicznym. Można je umieścić bezpośrednio na @implementationbloku. A kiedy to zrobisz, są one faktycznie prywatne, bez względu na modyfikatory widoczności, ponieważ nie są nawet widoczne dla osób spoza tego pliku.
— BJ Homer

14

Ważne jest, aby zrozumieć, co to znaczy, gdy ktoś mówi, że nie masz dostępu do @private zmiennej instancji. Prawdziwa historia jest taka, że ​​kompilator da ci błąd, jeśli spróbujesz uzyskać dostęp do tych zmiennych w kodzie źródłowym. W poprzednich wersjach GCC i XCode zamiast błędu pojawiałoby się ostrzeżenie.

Tak czy inaczej, w czasie wykonywania wszystkie zakłady są wyłączone. Te @privatei @protectedivars mogą być dostępne przez obiekt dowolnej klasy. Te modyfikatory widoczności utrudniają kompilację kodu źródłowego w kod maszynowy, który narusza intencję modyfikatorów widoczności.

Nie polegaj na modyfikatorach widoczności w systemie ivar! W ogóle nie zapewniają. Są one przeznaczone wyłącznie do egzekwowania w czasie kompilacji życzeń budowniczego klas.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.