Was bedeutet "@private" in Objective-C?

Antworten:

186

Es handelt sich um einen Sichtbarkeitsmodifikator. Dies bedeutet, dass Instanzvariablen, die als deklariert @privatesind, nur von Instanzen derselben Klasse aufgerufen werden können . Auf private Mitglieder können Unterklassen oder andere Klassen nicht zugreifen.

Beispielsweise:

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

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

Zur Verdeutlichung sind Methoden in Objective-C immer öffentlich. Es gibt jedoch Möglichkeiten, Methodendeklarationen zu "verbergen". Weitere Informationen finden Sie in dieser Frage .

hbw
quelle
Was ist mit Instanzvariablen, die nach der Implementierung in geschweiften Klammern stehen? Sind sie immer privat?
John Henckel
Ich weiß, dass es alt ist ... Aber es ist kein Sichtbarkeitsmodifikator. Es ist ein Zugriffsmodifikator. Es ist eine wichtigere Unterscheidung in C ++, aber es ist auch eine Unterscheidung in Objective-C. Die Variable ist für den Compiler sichtbar. Der Compiler lässt Sie einfach nicht darauf zugreifen.
Gnasher729
161

Wie gesagt, es ist ein Sichtbarkeitsmodifikator. @privatebedeutet, dass auf ivar (Instanzvariable) nur direkt aus einer Instanz derselben Klasse zugegriffen werden kann. Das bedeutet Ihnen jedoch möglicherweise nicht viel. Lassen Sie mich Ihnen ein Beispiel geben. Der initEinfachheit halber werden wir die Methoden der Klassen als Beispiele verwenden. Ich werde inline kommentieren, um auf interessante Punkte hinzuweisen.

@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;
}

Um Ihre Frage zu beantworten, schützt @private ivars vor dem Zugriff durch eine Instanz einer anderen Klasse. Beachten Sie, dass zwei Instanzen von MyFirstClass direkt auf alle Ivars des jeweils anderen zugreifen können. Es wird davon ausgegangen, dass der Programmierer diese Fähigkeit mit Bedacht einsetzen wird, da er direkt die vollständige Kontrolle über diese Klasse hat.

BJ Homer
quelle
20
Es sollte erwähnt werden, dass es ungewöhnlich ist, @public, @proteced und @private in Objective-C zu verwenden. Der bevorzugte Ansatz besteht darin, immer Accessoren zu verwenden.
Georg Schölly
1
@Georg, aber wie erzwingen Sie die Verwendung von Accessoren, wenn Sie Ihre Ivars nicht mit eingeschränkter Sichtbarkeit markieren?
Greg Maletic
5
@Georg Schölly: Da xcode 4.x + automatisch @privatedie Vorlage für ein Objekt einfügt , ist dies nicht mehr so ​​ungewöhnlich.
Morgengrauen
1
@Georg Ich denke, @private, @protected kann für Fälle verwendet werden, in denen Vererbung beteiligt ist, habe es aber nicht persönlich verwendet :)
chunkyguy
5
Es sollte beachtet werden, dass es heutzutage kaum einen Grund gibt, Instanzvariablen in den öffentlichen Header aufzunehmen. Sie können direkt auf dem @implementationBlock platziert werden . Und sobald Sie dies tun, sind sie unabhängig von den Sichtbarkeitsmodifikatoren praktisch privat, da sie für niemanden außerhalb dieser Datei sichtbar sind.
BJ Homer
14

Es ist wichtig zu verstehen, was es bedeutet, wenn jemand sagt, dass Sie nicht auf eine @privateInstanzvariable zugreifen können. Die wahre Geschichte ist, dass der Compiler Ihnen einen Fehler gibt, wenn Sie versuchen, auf diese Variablen in Ihrem Quellcode zuzugreifen. In früheren Versionen von GCC und XCode wurde anstelle eines Fehlers nur eine Warnung angezeigt.

In jedem Fall sind zur Laufzeit alle Wetten ungültig. Auf diese @privateund @protectedivars kann ein Objekt jeder Klasse zugreifen. Diese Sichtbarkeitsmodifikatoren machen es nur schwierig, den Quellcode in Maschinencode zu kompilieren, der die Absicht der Sichtbarkeitsmodifikatoren verletzt.

Verlassen Sie sich aus Sicherheitsgründen nicht auf ivar-Sichtbarkeitsmodifikatoren! Sie bieten überhaupt keine. Sie dienen ausschließlich der Durchsetzung der Wünsche des Klassenbauers zur Kompilierungszeit.

Jeff Wolski
quelle