Que signifie «@private» dans Objective-C?

Réponses:

186

Il s'agit d'un modificateur de visibilité - cela signifie que les variables d'instance déclarées comme @privatene sont accessibles qu'aux instances de la même classe . Les membres privés ne sont pas accessibles par les sous-classes ou autres classes.

Par exemple:

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

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

De plus, pour clarifier, les méthodes sont toujours publiques dans Objective-C. Il existe cependant des moyens de "masquer" les déclarations de méthode - consultez cette question pour plus d'informations.

hbw
la source
Qu'en est-il des variables d'instance qui se trouvent entre les accolades après la @implementation? Sont-ils toujours privés?
John Henckel
Je sais que c'est vieux ... Mais ce n'est pas un modificateur de visibilité. C'est un modificateur d'accès. C'est une distinction plus importante en C ++, mais c'est aussi une distinction en Objective-C. La variable est visible par le compilateur. Le compilateur ne vous permet tout simplement pas d'y accéder.
gnasher729
161

Comme l'a dit htw, c'est un modificateur de visibilité. @privatesignifie que l'ivar (variable d'instance) n'est accessible directement qu'à partir d'une instance de la même classe. Cependant, cela ne signifie peut-être pas grand-chose pour vous, alors laissez-moi vous donner un exemple. Nous utiliserons les initméthodes des classes comme exemples, par souci de simplicité. Je commenterai en ligne pour signaler les éléments d'intérêt.

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

Donc, pour répondre à votre question, @private protège les ivars contre l'accès par une instance de toute autre classe. Notez que deux instances de MyFirstClass peuvent accéder directement à tous les ivars respectifs; il est supposé que puisque le programmeur a un contrôle complet direct sur cette classe, il utilisera cette capacité à bon escient.

BJ Homer
la source
20
Il convient de mentionner qu'il est rare d'utiliser @public, @proteced et @private dans Objective-C. L'approche préférée consiste à toujours utiliser des accesseurs.
Georg Schölly,
1
@Georg, mais comment imposez-vous l'utilisation d'accesseurs à moins que vous ne marquiez vos ivars avec une visibilité limitée?
Greg Maletic
5
@Georg Schölly: Étant donné que xcode 4.x + place automatiquement @privatele modèle pour un objet, il n'est plus si rare.
dawg
1
@Georg Je pense que @private, @protected peut être utilisé dans les cas où l'héritage est impliqué, mais je ne l'ai pas utilisé personnellement :)
chunkyguy
5
Il convient de noter que de nos jours, il y a très peu de raisons de mettre des variables d'instance dans l'en-tête public. Ils peuvent être placés directement sur le @implementationbloc. Et une fois que vous faites cela, ils sont effectivement privés quels que soient les modificateurs de visibilité, car ils ne sont même pas visibles par quiconque en dehors de ce fichier.
BJ Homer
14

Il est important de comprendre ce que cela signifie lorsque quelqu'un dit que vous ne pouvez pas accéder à une @privatevariable d'instance. La vraie histoire est que le compilateur vous donnera une erreur si vous essayez d'accéder à ces variables dans votre code source. Dans les versions précédentes de GCC et XCode, vous receviez simplement un avertissement au lieu d'une erreur.

De toute façon, au moment de l'exécution, tous les paris sont désactivés. Ces objets @privateet @protectedivars sont accessibles par un objet de n'importe quelle classe. Ces modificateurs de visibilité rendent difficile la compilation du code source en code machine qui viole l'intention des modificateurs de visibilité.

Ne vous fiez pas aux modificateurs de visibilité ivar pour la sécurité! Ils n'en fournissent aucun. Ils sont strictement destinés à l'application au moment de la compilation des souhaits du constructeur de classe.

Jeff Wolski
la source