在Objective-C中,"@private" 是什么意思?

283

@private 在 Objective-C 中表示私有成员变量。


这个问题在第53期的播客中有讨论!(https://stackoverflow.blog/2009/05/14/podcast-53/) - StayOnTarget
3个回答

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中方法始终是公共的。然而,有隐藏方法声明的方式 -- 查看这个问题获取更多信息。


在 @implementation 后面的大括号中定义的实例变量是私有的吗? - John Henckel
我知道这很老旧... 但它不是可见性修饰符。它是一个访问修饰符。在C++中这是一个更重要的区别,但在Objective-C中也是一个区别。变量对编译器是可见的,只是编译器不允许你访问它。 - gnasher729

163
正如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可以保护实例变量不被其他类的实例访问。请注意,两个MyFirstClass的实例可以直接访问彼此的所有实例变量;这是因为程序员可以直接完全控制这个类,他会明智地使用这种能力。


21
值得一提的是,在Objective-C中很少使用@public、@protected和@private。首选方法是始终使用访问器。 - Georg Schölly
1
@Georg,但是如果你不使用受限制的可见性标记你的实例变量,你如何强制使用访问器呢? - Greg Maletic
5
自从Xcode 4.x+自动在对象的模板中加入了@private,这种情况就不再那么罕见了。 - dawg
1
@Georg 我认为 @private 和 @protected 可以用于涉及继承的情况,不过我个人没有使用过 :) - chunkyguy
6
值得注意的是,现在很少有理由将实例变量放在公共头文件中。它们可以直接放置在@implementation块中。一旦这样做了,无论可见性修饰符如何,它们都是有效的私有变量,因为它们甚至对那个文件之外的任何人都不可见。 - BJ Homer
显示剩余3条评论

15
重要的是要理解当有人说你不能访问一个@private实例变量时,这意味着什么。真相是,如果您在源代码中尝试访问这些变量,则编译器会给出错误。在早期版本的GCC和XCode中,您只会收到警告而不是错误。
无论哪种方式,在运行时,一切皆有可能。这些@private@protected实例变量可以被任何类的对象访问。这些可见性修饰符只是使将源代码编译成违反可见性修饰符意图的机器代码变得困难。
请勿依赖ivar可见性修饰符来保护安全性!它们根本没有提供任何安全性。它们严格用于在编译时执行类构建者的愿望。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接