9

我最近更新到 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 行显示“它正在运行”消息。)

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

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

4

2 回答 2

19

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

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

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

从那个链接后面还有一个历史记录,解决了我们过去必须在接口块中声明 ivars 的事实:

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

对于隐私问题,是的,这些变量是真正私有的——它们的行为就像在与指令的接口中声明的 ivars @private。这意味着默认情况下子类无法访问它们。然而,它们的可见性可以使用@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,所以这只是几个月前的发布。海湾合作委员会不会这样做。

于 2012-05-02T04:49:56.260 回答
2

它很新,只要您需要的任何编译器支持它,它就有效。

这对于最小化您的依赖关系非常有用——包含和转发可能主要在实现文件中。出于这个原因,如果您使用的所有编译器都支持它,那么对于您的 ivars 来说,它是一个比在@interface块中更好的地方。

最后一个警告是我们当前(2012 年 2 月 2 日)的调试器不支持这一点。

于 2012-05-02T04:49:36.940 回答