Что означает «@private» в Objective-C?

Ответы:

186

Это модификатор видимости - это означает, что переменные экземпляра, объявленные как, @privateмогут быть доступны только экземплярам того же класса . Частные члены не могут быть доступны для подклассов или других классов.

Например:

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

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

Также, чтобы уточнить, методы всегда общедоступны в Objective-C. Однако есть способы «скрыть» объявления методов - см. Этот вопрос для получения дополнительной информации.

HBW
источник
Как насчет переменных экземпляра, которые находятся в фигурных скобках после @implementation? Они всегда приватны?
Джон Хенкель
Я знаю, что он старый ... Но это не модификатор видимости. Это модификатор доступа. Это более важное различие в C ++, но также и в Objective-C. Переменная видна компилятору. Компилятор просто не позволяет вам получить к нему доступ.
gnasher729
161

Как сказал htw, это модификатор видимости. @privateозначает, что ivar (переменная экземпляра) может быть доступен только непосредственно из экземпляра того же класса. Однако, это не может много значить для вас, поэтому позвольте мне привести вам пример. Мы будем использовать initметоды классов в качестве примеров, для простоты. Я прокомментирую, чтобы указать на интересные вещи.

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

Таким образом, чтобы ответить на ваш вопрос, @private защищает ivars от доступа экземпляра любого другого класса. Обратите внимание, что два экземпляра MyFirstClass могут напрямую обращаться ко всем иварам друг друга; предполагается, что, поскольку программист имеет полный контроль над этим классом напрямую, он будет использовать эту способность с умом.

Би Джей Гомер
источник
20
Следует отметить, что в Objective-C редко используются @public, @proteced и @private. Предпочтительный подход - всегда использовать средства доступа.
Георг Шолли
1
@ Георг, но как вы обеспечите использование аксессоров, если вы не помечаете свои ивары ограниченной видимостью?
Грег Малетик
5
@ Георг Шолли: Поскольку xcode 4.x + автоматически вставляет @privateшаблон для объекта, это уже не так уж редко.
Дауг
1
@ Georg Я думаю, @private, @protected можно использовать в тех случаях, когда происходит наследование, но я не использовал его лично :)
chunkyguy
5
Следует отметить, что в наши дни очень мало причин помещать переменные экземпляра в публичный заголовок. Их можно разместить прямо на @implementationблоке. И после того, как вы это сделаете, они будут фактически приватными, независимо от модификаторов видимости, поскольку они даже не видны никому за пределами этого файла.
Би Джей Гомер
14

Важно понимать, что это значит, когда кто-то говорит, что вы не можете получить доступ к @privateпеременной экземпляра. Реальная история в том, что компилятор выдаст вам ошибку, если вы попытаетесь получить доступ к этим переменным в вашем исходном коде. В предыдущих версиях GCC и XCode вы просто получали предупреждение вместо ошибки.

В любом случае, во время исполнения все ставки выключены. Эти @privateи @protectedивары могут быть доступны для объекта любого класса. Эти модификаторы видимости просто затрудняют компиляцию исходного кода в машинный код, который нарушает намерение модификаторов видимости.

Не полагайтесь на модификаторы видимости ivar для обеспечения безопасности! Они не предоставляют ничего вообще. Они предназначены исключительно для исполнения пожеланий класс-строителя.

Джефф Вольски
источник