O que significa "@private" no Objective-C?

Respostas:

186

É um modificador de visibilidade - significa que as variáveis ​​de instância declaradas como @privatepodem ser acessadas apenas por instâncias da mesma classe . Membros privados não podem ser acessados ​​por subclasses ou outras classes.

Por exemplo:

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

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

Além disso, para esclarecer, os métodos são sempre públicos no Objective-C. Porém, existem maneiras de "ocultar" as declarações de método - consulte esta pergunta para obter mais informações.

hbw
fonte
E as variáveis ​​de instância que estão entre chaves depois da implementação? Eles são sempre privados?
John Henckel
Eu sei que é velho ... Mas não é um modificador de visibilidade. É um modificador de acesso. É uma distinção mais importante em C ++, mas também em Objective-C. A variável é visível para o compilador. O compilador simplesmente não permite que você acesse.
gnasher729
161

Como o htw disse, é um modificador de visibilidade. @privatesignifica que o ivar (variável de instância) só pode ser acessado diretamente de dentro de uma instância da mesma classe. No entanto, isso pode não significar muito para você, então deixe-me dar um exemplo. Usaremos os initmétodos das classes como exemplos, por uma questão de simplicidade. Vou comentar em linha para apontar itens de interesse.

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

Portanto, para responder sua pergunta, o @private protege o ivars do acesso por uma instância de qualquer outra classe. Observe que duas instâncias do MyFirstClass podem acessar todos os ivars um do outro diretamente; presume-se que, como o programador tenha controle completo sobre essa classe diretamente, ele usará essa habilidade com sabedoria.

BJ Homer
fonte
20
Deve-se mencionar que é incomum usar @public, @proteced e @private no Objective-C. A abordagem preferida é sempre usar acessadores.
Georg Schölly
1
@Georg, mas como você reforça o uso de acessadores, a menos que marque seus ivars com visibilidade restrita?
Greg Maletic
5
@Georg Schölly: Como o xcode 4.x + automaticamente coloca @privateo modelo de um objeto, não é mais tão incomum.
Dawg
1
@Georg Eu acho que @private, @protected pode ser usado para casos onde a herança está envolvido, não usei pessoalmente embora :)
chunkyguy
5
Deve-se notar que atualmente, há muito pouco motivo para colocar variáveis ​​de instância no cabeçalho público. Eles podem ser colocados diretamente no @implementationbloco. E depois que você faz isso, eles são efetivamente privados, independentemente dos modificadores de visibilidade, pois nem são visíveis a ninguém fora desse arquivo.
BJ Homer
14

É importante entender o que significa quando alguém diz que você não pode acessar uma @privatevariável de instância. A história real é que o compilador apresentará um erro se você tentar acessar essas variáveis ​​no seu código-fonte. Nas versões anteriores do GCC e do XCode, você apenas receberia um aviso em vez de um erro.

De qualquer forma, em tempo de execução, todas as apostas estão desativadas. Estes @privatee @protectedivars podem ser acessados ​​por um objeto de qualquer classe. Esses modificadores de visibilidade apenas dificultam a compilação do código-fonte no código de máquina que viola a intenção dos modificadores de visibilidade.

Não confie nos modificadores de visibilidade ivar para segurança! Eles não fornecem nenhum. Eles são estritamente para a imposição em tempo de compilação dos desejos do construtor de classe.

Jeff Wolski
fonte