51

我想创建一个无法从外部访问的实例变量。在objective-c中可能会有这样的事情吗?我记得苹果有私有变量之类的东西,但如果人们知道它们,他们就可以使用它们。Apple 称其为“私有 API”,但显然其他人如果发现其中的内容,就可以访问这些内容。

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

@interface MyClass : NSObject {
    CGFloat weight;
}

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

我也知道 Apple 添加了一个 _inFrontOfTheirPrivateInstanceVariables,但他们在某处说他们不喜欢看到其他人这样做,因为他们可能会在这样做时覆盖意外隐藏的实例变量。

这里有什么诀窍?

4

7 回答 7

60

您可以使用 中的@private关键字{}将所有后续变量声明设为私有。默认可见性是@protected(类似于protectedJava 中的),并且通常效果很好。您必须专门声明一个变量,@public以便在类外部直接访问它。

此 Apple 文档包含有关变量范围和可见性的更多详细信息。

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

至于变量前面的前导 _,请注意 Apple 还为“私有”方法保留此前缀。保证您避免问题的最佳方法是对您自己的变量和方法使用正常的命名约定。但是,除非您从 Cocoa(NSObject 除外)继承某些东西,否则您可以相当有信心不会遇到问题。

于 2009-08-11T19:41:53.353 回答
31

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

@interface ClassName()
{
@private
// private variables here
}
@end

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

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

于 2011-06-09T15:00:11.110 回答
9

您可以通过将私有方法仅放在@implementation 中而不是@interface 中来定义它们。

类似地,您可以在@implementation 开头的匿名块内定义私有实例变量 - 就像在@interface 内为公共 ivars 所做的那样。

请参阅以下示例。

@interface EXClass : NSObject
{
uint8_t publicInteger;
float publicFloat;
}

-(void)publicMethod;
@end

@implementation EXClass
{
uint8_t privateInteger;
float privatefloat;
}

-(BOOL)privateMethod {
return FALSE;
}

请记住,Objective-C 方法在运行时作为消息发送(而不是 C++ 的编译时绑定),因此 respondsToSelector: 仍将返回 true 并且 performSelector: 仍将调用该方法。ivars 将是完全私有的。

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

于 2012-08-19T19:27:43.143 回答
3

默认情况下,Objective-C 中的所有 iVar 都受到保护。如果您不编写访问器方法,那么其他类将无法看到变量。

两个例外是类别和子类。

于 2009-08-11T19:45:39.713 回答
2

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

命名实例变量和数据类型

我还记得 Wil Shipley 和其他一些 OS X 开发人员之间关于下划线的对话。由于 Obj-C 编译器的工作方式,如果 Apple 将新的实例变量添加到其框架中的类中,将导致所有使用这些框架的应用程序都需要重新编译。就预先存在的实例变量而言,当您踩到某个实例变量时应该会收到警告。

于 2009-08-11T20:49:58.867 回答
2

我在 Apple 的示例应用程序 (PaintGL) 中看到了以下用法

在 .m 文件中

@interface MyClass (private)
  - (void) privateMethod();
  @property(...) myProperty;
@end

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

于 2013-03-05T18:26:17.490 回答
1

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

我最好的方法:

在 .m 文件的实现块中使用它。然后不可见并阻塞KVC,使KVC不起作用

@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
于 2013-09-06T09:30:29.497 回答