如何声明在类实例外部不可见或不可用的实例变量和方法?

时间:2011-04-28 23:45:51

标签: iphone objective-c xcode ios

我已经浏览了很多关于这个主题的帖子。也许我没有碰到“那个”,有人会指出我朝这个方向发展。问题很简单,可能有一个简单的答案。

如果你有两个ivars,比如说,“public_ivar”和“private_ivar”,你应该在哪里/如何声明它们以便public是公共的,什么是private不会以任何方式暴露给任何查看头文件的人?

“public_method”和“private_method”的情况下的同样问题。

我喜欢干净的头文件(在其他语言中)只暴露我希望别人看到的方法和ivars。您应该能够发布您的头文件,而不会遇到某人访问他们不应该访问的东西的危险。你如何在Objective-C中做到这一点。

例如,假设我决定我需要使用ivar来跟踪所有需要访问此信息的各种类方法之间的某些数据,计数器或类似的东西。如果在@interface下的标题中传统地声明了这个ivar,那么它的存在是公开广告的,任何创建该类实例的人都可以使用它。理想的情况是,在类实现之外,这个ivar根本不可见。

3 个答案:

答案 0 :(得分:17)

您可以在类扩展中声明实例变量或声明的属性。由于类扩展是在实现文件中声明的(即,不是头文件),因此检查头文件的人不会看到它们。例如,在头文件中:

@interface SomeClass : NSObject
@end

并在实施文件中:

@interface SomeClass ()
@property (nonatomic, assign) int privateInt;
@end

@implementation SomeClass

@synthesize privateInt;
…
@end

@interface SomeClass () {
    int privateInt;
}
@end

@implementation SomeClass
…
@end

请注意,在运行时期间没有任何内容阻止访问私有/类扩展实例变量(或类扩展中声明的属性的访问器方法)。我已经写了一篇相当详细的帖子,作为Stack Overflow上另一个问题的答案:Does a private @property create an @private instance variable?

编辑:类扩展中的实例变量在WWDC 2010会话144中提供。

编辑:“使用Clang / LLVM 2.0编译器,您还可以在类扩展中声明属性和实例变量。”

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1

答案 1 :(得分:4)

使用class extensions添加到实现文件中的类。类扩展基本上是一个带有一些奖励的未命名类别:在其中声明的属性可以合成,并且在其中声明的任何内容必须在主实现中,因此编译器可以检查以确保您没有错过实现。您必须在实现之前放置类扩展。您不能直接在类扩展中添加实例变量,但可以添加属性。当您为没有相应实例变量的属性合成访问器时,新运行时(os x 10.5及更高版本以及所有iOS版本,我相信)将自动创建实例变量。这意味着您无法创建自己的访问者,除非您将实例变量放在标题中。可以不受限制地将私有方法添加到类扩展中,但正如Anomie所指出的,如果你知道它们被称为什么,技术上可以使用它们,并且使用类转储,没有什么是安全的。

类扩展的示例用法:

@interface MyClass ()
@property (retain) id privateIvar;
@property (readwrite) id readonlyProperty; // bonus! class extensions can be used to make a property that is publicly readonly and privately readwrite
- (void)privateMethod;
@end
@implementation MyClass
@synthesize privateIvar; // the runtime will create the actual ivar, and we just access it through the property
- (void)privateMethod {
    ...
}
...

创建“实例变量”而不将它们放入标题或使用属性的另一种方法是使用associative references,它在运行时将数据添加到对象。它们在技术上与实例变量不同,它们的语法更复杂。由于它们还需要新的运行时,因此只有两个原因你真的想要使用它们:你想在一个类别中添加一个实例变量(在这个问题的范围之外),或者你需要它真的真的私人。关联引用不会在编译代码中创建任何方法或添加到类的定义中,因此如果您不为它们创建包装器,则在添加数据后不询问对象就无法找到它们。请参阅我链接的页面底部以获取完整的使用示例。

答案 2 :(得分:2)

您可以使用@private指定ivars是私有的。但是,无法将方法设为私有。即使该方法未在头文件中列出,如果有人知道他们可以调用它的名称和参数。