我想创建一个无法从外部访问的实例变量。在objective-c中有可能是这样的吗?我记得Apple有私有变量和类似的东西,但如果人们知道它们,他们就可以使用它们。 Apple称之为“私有API”,但显然其他人可以访问那些东西,如果他们发现那里有什么。
到目前为止,我认为像这样的东西会创建一个私有实例变量:
@interface MyClass : NSObject {
CGFloat weight;
}
没有@property,没有@synthesize,只是上面的声明。
我也知道Apple添加了一个_inFrontOfTheirPrivateInstanceVariables,但他们说他们不喜欢看到其他人这样做,因为他们可能会在执行此操作时覆盖意外隐藏的实例变量。
这里的诀窍是什么?
答案 0 :(得分:60)
您可以使用@private
中的{}
关键字将所有后续变量声明设为私有。默认可见性为@protected
(类似于Java中的protected
),通常效果很好。您必须专门将变量声明为@public
,才能在课堂外直接访问它。
This Apple documentation有关于变量范围和可见性的更多详细信息。
“私有API”和私有变量之间也存在差异。在Objective-C中,您不能将方法设为私有 - 任何人都可以调用任何方法。有几种方法可以创建“秘密”方法,但这有点超出了这个问题的范围。以下是一些相关的SO问题:
就变量前面的前导_而言,请注意Apple还为“私有”方法保留此前缀。保证避免出现问题的最佳方法是为自己的变量和方法使用常规命名约定。但是,除非你从Cocoa(除了NSObject之外)继承了一些东西,否则你可以相信你不会遇到问题。
答案 1 :(得分:31)
在XCode 4及更高版本中使用新的LLVM编译器,您可以在实现(.m)文件中的默认类别中声明@private
个变量:
@interface ClassName()
{
@private
// private variables here
}
@end
@implementation ClassName
// you can use private variables here
@end
我发现这很方便,因为我讨厌污染私有变量带入我的头文件。
答案 2 :(得分: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:仍将调用该方法。伊娃将是完全私密的。
但是,如果您正在创建一个库,理论上没有人会知道您未在头文件中声明的任何方法。
答案 3 :(得分:3)
Objective-C中的所有iVars都默认受保护。如果不编写访问器方法,则其他类将无法查看变量。
两个例外是类别和子类。
答案 4 :(得分:2)
用于命名实例变量的Apple文档没有明确警告不要像私有方法文档那样在实例变量的名称中使用下划线。
Naming Instance Variables and Data Types
我还记得Wil Shipley和其他一些OS X开发人员之间的对话关注下划线。由于Obj-C编译器的工作方式,如果Apple要在其框架中向类添加新的实例变量,则会导致需要重新编译使用这些框架的所有应用程序。就预先存在的实例变量而言,当您单步执行变量时,您应该收到警告。
答案 5 :(得分:2)
我在Apple的示例应用程序(PaintGL)中看到了以下用法
在.m文件中
@interface MyClass (private)
- (void) privateMethod();
@property(...) myProperty;
@end
免责声明:示例应用程序只有方法声明,我看到私有属性声明in this SO thread
答案 6 :(得分: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