这是在Objective-C中定义私有实例变量的新方法吗?

时间:2012-05-02 04:44:13

标签: objective-c

我最近更新到Xcode 4.3.2并发现我现在可以在@implementation块中声明私有实例变量,如下所示:

@interface TestClass : NSObject
@property (nonatomic, copy) NSString *testProp;
@end

@implementation TestClass {
    NSString *_testPropStore;
}

- (NSString *)testProp { return _testPropStore; }
- (void)setTestProp:(NSString *)testProp { _testPropStore = [testProp copy]; }

- (id)init {
    if (self = [super init]) {
        _testPropStore = nil;
    }
    return self;
}

@end

注意NSString *_testPropStore大括号内的@implementation行。

我还使用以下代码进行了测试:

TestClass *c1 = [[TestClass alloc] init];
TestClass *c2 = [[TestClass alloc] init];

c1.testProp = @"Hello";
c2.testProp = @"World";

NSAssert(c1.testProp == c2.testProp, @"It's working!");

这似乎工作得很好。 (也就是说,应用程序在NSAssert行崩溃了“It is working”消息。)

这是Objective-C的一个新功能,用于声明私有实例变量吗?由于我偶然发现了这个,我很想知道它是否只是用于声明私有实例变量,还是会有任何我不知道的副作用?

我找不到任何相关文件,因为大多数带有private这类字样的问题最终都得到了关于如何在不同的私人扩展类别上声明它们的答案。

2 个答案:

答案 0 :(得分:19)

这是真实的,它是新的方式,*它很棒,而且,是的,它在文档中。 The Objective-C Programming Language,与我们获得该语言的实际规范一样接近,有如下说法:

  

类的定义与其声明的结构非常相似。它以@implementation指令开头,以@end指令结束。此外,类可以在@implementation指令后面的大括号中声明实例变量:

@implementation ClassName
{
    // Instance variable declarations.
}
// Method definitions.
@end

还有一个历史记录从该链接稍微回过头来解决我们过去必须在接口块中声明ivars的事实:

  

历史上,接口需要声明类的实例变量,这些数据结构是类的每个实例的一部分。 ...实例变量表示实现细节,通常不应在类本身之外访问。此外,您可以在实现块中声明它们或使用声明的属性合成它们。因此,通常不应在公共接口中声明实例变量,因此应省略大括号。

对于隐私问题,是的,这些变量是真正的私有 - 它们就像在@private指令的接口中声明的ivars一样。这意味着默认情况下子类无法访问它们。但是,可以使用@protected或(如果出于某些奇怪的原因需要)更改其可见性@public

@interface Stuper : NSObject 
@end

@implementation Stuper
{
    @protected
    NSString * sangfroid;
}
@end

@interface Stub : Stuper
- (void)setSangfroid: (NSString *)newSangfroid;
@end

@implementation Stub

- (void)setSangfroid: (NSString *)newSangfroid {
    sangfroid = [newSangfroid copy];
}

*你必须使用clang> 3.0,我相信,所以这就是几个月前的帖子。海湾合作委员会不会这样做。

答案 1 :(得分:2)

这是非常新的,只要您需要的任何编译器都支持它,它就是有效的。

最大限度地减少依赖关系 - 包含和转发可能主要在实现文件中。出于这个原因,如果您使用的所有编译器都支持它,那么对于您的ivars而言,它比@interface块更好。

最后一点需要注意的是,我们当前的(2012年2月)调试器不支持此功能。