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 .

Grubaski
źródło
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ść.

BJ Homer
źródło
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.

Jeff Wolski
źródło