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

时间:2022-09-07 07:42:24

I've recently updated to Xcode 4.3.2 and found that I can now declare private instance variables inside @implementation block like so:

我最近更新到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

Notice the NSString *_testPropStore line inside @implementation brace block.

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

I've also tested with the following code:

我还测试了以下代码:

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

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

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

Which seems to work fine. (That is, the app crashes with the "It's working" message at the NSAssert line.)

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

So is this a new feature of Objective-C for declaring private instance variables? Since I discovered this by accident, I would love to know if it is just for declaring private instance variables or will there be any side effects that I'm not aware of?

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

I couldn't find any relevant document since most questions of such type with the word private just ended up with answers on how to declare them on a private extension category which is different.

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

2 个解决方案

#1


19  

It's for real, it's the new way,* it's great, and, yes, it's in the docs. The Objective-C Programming Language, which is as close as we get to having an actual spec for the language, has the following to say:

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

The definition of a class is structured very much like its declaration. It begins with an @implementation directive and ends with the @end directive. In addition, the class may declare instance variables in braces after the @implementation directive:

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

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

There's also a historical note a little ways back from that link, addressing the fact that we used to have to declare ivars in the interface block:

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

Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. ... Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.

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

For the question of privacy, yes, these variables are truly private -- they act like ivars declared in the interface with the @private directive. This means that subclasses can't access them, by default. Their visibility can be changed, however, using either @protected or (if necessary for some bizarre reason) @public:

对于隐私问题,是的,这些变量是真正的私有 - 它们就像在@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];
}

*You have to use clang > 3.0, I believe, so that's just a few months ago as of this posting. GCC won't do it.

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

#2


2  

It's pretty new and it's valid as long as any compiler you need supports it.

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

It's great for minimizing your dependencies -- the includes and forwards may largely be in the implementation file. For this reason, and if all the compilers you use support it, then it's a better place for your ivars than in the @interface block.

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

A final caveat is that our current (may.2.2012) debuggers do not support this.

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

#1


19  

It's for real, it's the new way,* it's great, and, yes, it's in the docs. The Objective-C Programming Language, which is as close as we get to having an actual spec for the language, has the following to say:

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

The definition of a class is structured very much like its declaration. It begins with an @implementation directive and ends with the @end directive. In addition, the class may declare instance variables in braces after the @implementation directive:

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

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

There's also a historical note a little ways back from that link, addressing the fact that we used to have to declare ivars in the interface block:

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

Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. ... Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.

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

For the question of privacy, yes, these variables are truly private -- they act like ivars declared in the interface with the @private directive. This means that subclasses can't access them, by default. Their visibility can be changed, however, using either @protected or (if necessary for some bizarre reason) @public:

对于隐私问题,是的,这些变量是真正的私有 - 它们就像在@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];
}

*You have to use clang > 3.0, I believe, so that's just a few months ago as of this posting. GCC won't do it.

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

#2


2  

It's pretty new and it's valid as long as any compiler you need supports it.

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

It's great for minimizing your dependencies -- the includes and forwards may largely be in the implementation file. For this reason, and if all the compilers you use support it, then it's a better place for your ivars than in the @interface block.

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

A final caveat is that our current (may.2.2012) debuggers do not support this.

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