类变量定义在@implementation而不是@interface?

问题描述 投票:0回答:7

我是 Objective-C 的新手,但我对一些我在其他地方没有真正看到过的东西感到好奇。

谁能告诉我在

@interface
块中声明的私有变量与在类方法之外的
@implementation
块中声明的变量之间有什么区别,即:

@interface Someclass : NSObject {

 NSString *forExample;

}

@end

@implementation Someclass

 NSString *anotherExample;

-(void)methodsAndSuch {}

@end

似乎这两个变量(

forExample
anotherExample
)在整个班级中都是同样可访问的,我真的找不到它们行为的差异。第二种形式也叫实例变量吗?

objective-c
7个回答
35
投票

后者没有定义实例变量。相反,它在 .m 文件中定义一个全局变量。这样的变量不是任何对象实例所独有的,也不是任何对象实例的一部分。

此类全局变量有其用途(大致相当于 C++ 静态成员;例如存储单例实例),但通常您会在 @implementation 指令之前在文件顶部定义它们。


24
投票

他们非常不同!

@implementation
中的变量是一个全局变量,对于每个实例来说并不是唯一的。想象一下,两个变量都有访问器,以明显的方式编写。那么行为上的差异如下所示:

Someclass* firstObject = [[Someclass alloc] init];
Someclass* secondObject = [[Someclass alloc] init];

//forExample is an instance variable, and is unique to each instance.
[firstObject setForExample:@"One"];
[secondObject setForExample:@"Two"];
NSLog(@"%@",[firstObject forExample]); //Result: "One"
NSLog(@"%@",[secondObject forExample]); //Result: "Two"

//anotherExample is a global variable, and is NOT unique to each instance.
[firstObject setAnotherExample:@"One"];
[secondObject setAnotherExample:@"Two"];
NSLog(@"%@",[firstObject anotherExample]); //Result: "Two" (!)
NSLog(@"%@",[secondObject anotherExample]); //Result: "Two"

//Both instances return "Two" because there is only ONE variable this time.
//When secondObject set it, it replaced the value that firstObject set.

如果您正在寻找这种行为,那么最好使用类变量,如下所示:

static NSString* yetAnotherExample = nil;

然后您可以使用类方法与变量进行交互,并且它显然是特定于类的(而不是特定于实例或全局的)。


5
投票

如果您在 @implementation 部分中声明一个变量,那么您实际上是在创建一个全局变量,该变量在任何地方都可见(在应用程序的每个方法中)。

成员变量只能在@interface部分声明。它们只能在班级本身中访问。


3
投票

在我看来,与其他 OOP 概念相比,在

@implementation
块内声明的私有块有点危险。爪哇。它看起来像成员变量,但有点静态。

新手程序员很容易被它愚弄。我编写了一个测试程序并对这种行为感到惊讶。

@interface SomeClass : NSObject
{
    NSString *forExample;
}

- (void) set:(NSString *)one another:(NSString *)another;
- (void)print;

@end

实施:

#import "SomeClass.h"

@implementation SomeClass

NSString *anotherExample;

- (void) set:(NSString *)one another:(NSString *)another
{
    forExample = one;
    anotherExample = another;
}

- (void)print{
    NSLog(@"One = %@, another = %@", forExample, anotherExample);
}

@end

测试:

- (void)testClass {
    SomeClass * s1 = [SomeClass new];
    [s1 set:@"one one" another:@"one another"];
    SomeClass *s2 = [SomeClass new];
    [s2 set:@"two one" another:@"two another"];
    [s1 print];
    [s2 print];
}

输出是,

One = one one, another = two another
One = two one, another = two another

2
投票

用一段代码来区分成员变量和全局变量:

@implementation MyClass {
  // It is an ivar, or called member variable
  // Can NOT be initialized when defined.
  // Can be accessed with `self->_i`
  int _i; 
}

- (instancetype)init {
    if (self = [super init]) {
       _i = 2; // should be initialized before being used.
    }
    return self;
}

int i = 9; // Global variable, and can be initialized when defined.
- (void)myFun {
    NSLog(@"%i, %i", self->_i, i);
}

@end


// Another file

extern int i;
NSLog(@"%i", i);

0
投票

需要明确的是,如果您将 IBOutlet 用于本地化 nibs/xibs,则永远不要将 IBOutlet 声明为全局变量(在实现中)。

我花了几个小时弄清楚为什么在任何给定时间只能在其中一个本地笔尖连接插座。

感谢您的问题和答案!


0
投票

本页内的答案已过时。 现在(2024)您可以在实现部分定义实例变量。

Objective-C 编程页面中“封装数据”页面中的“您可以定义没有属性的实例变量”部分。 封装数据

@implementation SomeClass {
    NSString *_anotherCustomInstanceVariable;
}
...
@end

我知道它已经过时了,但谷歌有时会在顶部显示这个答案,现在这是误导性的。所以我添加这个答案。

© www.soinside.com 2019 - 2024. All rights reserved.