关于C#:如何制作一个真正的私有实例变量?

How to make a real private instance variable?

我想创建一个不能从外部访问的实例变量。在Objective-C中,这样的事情是可能的吗?我记得苹果有私人变量和类似的东西,但是如果人们知道它们,他们可以使用它们。苹果称之为"私有API",但很明显,如果其他人发现其中的内容,他们可以访问这些内容。

到目前为止,我认为这样的事情会创建一个私有实例变量:

1
2
3
@interface MyClass : NSObject {
    CGFloat weight;
}

没有@property,没有@synthesis,只是上面的声明。

我也知道苹果公司增加了一个关于私有实例变量的信息,但他们在某个地方说他们不喜欢看到其他人这样做,因为这样做时,他们可能会意外地覆盖隐藏的实例变量。

这里的诀窍是什么?


您可以使用{}中的@private关键字使所有后续变量声明私有。默认可见性是EDCOX1×2Ω(它类似于Java中的EDCOX1×3),并且通常工作得很好。您必须特别声明一个变量为@public,以便在类外部直接访问它。

此Apple文档进一步详细介绍了变量范围和可见性。

"private api"和private变量也有区别。在Objective-C中,不能将方法设为私有的——任何人都可以调用任何方法。有几种方法可以创建"秘密"方法,但这有点超出了这个问题的范围。以下是一些相关的SO问题:

  • 关于Objective-C中的私有实例变量
  • 在Objective-C中"@private"是什么意思?
  • 是否可以在Objective-C中将方法声明为私有?
  • 在Objective-C中为类定义私有方法的最佳方法

至于变量前面的前导变量,请注意苹果还保留了"私有"方法的前缀。确保避免问题的最佳方法是为自己的变量和方法使用正常的命名约定。但是,除非您从cocoa子类(nsobject除外),否则您可以相当确信不会遇到问题。


使用Xcode4和更高版本中提供的新LLVM编译器,可以在实现(.m)文件中的默认类别中声明@private变量:

1
2
3
4
5
6
7
8
9
10
@interface ClassName()
{
@private
// private variables here
}
@end

@implementation ClassName
// you can use private variables here
@end

我觉得这很方便,因为我讨厌将污染私有变量带入我的头文件。


您可以通过只在@implementation而不是@interface中使用私有方法来定义私有方法。

同样,您可以在@implementation开始时在匿名块内定义私有实例变量,就像在@interface内定义公共ivar一样。

请参见以下示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@interface EXClass : NSObject
{
uint8_t publicInteger;
float publicFloat;
}

-(void)publicMethod;
@end

@implementation EXClass
{
uint8_t privateInteger;
float privatefloat;
}

-(BOOL)privateMethod {
return FALSE;
}

请记住,Objto-C方法在运行时作为消息发送(虽然不是C++的编译时绑定),所以ErrdStaseCopter:仍然返回true和PrExpReloStor:仍然调用该方法。IVARS将是完全私有的。

但是,如果您正在创建一个库,理论上没有人知道您在头文件中没有声明的任何方法。


Objective-C中的所有IVAR都默认受到保护。如果不编写访问器方法,其他类就无法看到变量。

这两个例外是类别和子类。


我在苹果的一个示例应用程序(paintgl)中看到了以下用法

在.m文件中

1
2
3
4
@interface MyClass (private)
  - (void) privateMethod();
  @property(...) myProperty;
@end

免责声明:示例应用程序只有方法声明,我在这个so线程中看到了私有属性声明


用于命名实例变量的Apple文档没有明确警告不要在实例变量名中使用下划线,就像私有方法文档那样。

命名实例变量和数据类型

我还记得WilShipley和其他几个OS X开发人员之间的一次对话,讨论了下面的要点。由于obj-c编译器的工作方式,如果苹果在其框架中向类添加一个新的实例变量,它将导致使用这些框架的所有应用程序都需要重新编译。对于预先存在的实例变量,您应该在单步执行时收到警告。


不能生成真正的私有实例变量。Objective-C是一种动态语言,因此可以访问任何变量(甚至@private)。

我的最佳方法:

在your.m文件的实现块中使用它。然后它就不可见了,会阻塞kvc,这样kvc就不会工作了。

1
2
3
4
5
6
7
8
9
10
11
@implementation ClassName {
    // default to @protected
    // but the subclasses can't see ivars created in the implementation block
    float number;
}

+ (BOOL)accessInstanceVariablesDirectly {
    return NO; // no KVC
}

@end