10

在 Objective-C 中访问实例变量的正确语法是什么?

假设我们有这个变量:

@interface thisInterface : UIViewController {
    NSMutableString *aString;
}

@property (nonatomic, retain) NSMutableString *aString;

并且它是合成的。

当我们想要访问它时,我们首先要分配和初始化它。用 Objective-C 编程大约一个月了,我已经看到了两种不同形式的语法。我见过人们做简单aString = [[NSMutableString alloc] initWithString:@"hi"]的事情,他们像这样分配字符串;我还看到人们开始使用它self.aString,然后他们继续初始化他们的 ivar。我想我只是想弄清楚初始化实例变量的最正确方法是什么,因为在前一个示例中,我收到了 EXC_BAD_ACCESS 错误。在添加了之后self.,它并没有出现。

如果这是一个重复的问题,请原谅我,但在阅读了一些关于 SO 的帖子后,这让我很好奇。我正在尝试使用 Objective-C 学习正确的语法,因为我更喜欢正确而不是草率。

4

7 回答 7

15

如果你已经@synthesize在 .m 文件中声明了一个属性,你只需像这样设置它:

self.aString = @"hi"; // or [[NSMutableString alloc] initWithString:@"hi"];

Usingself.varName利用了你的属性声明的实际作用——它为你处理新值的保留(因为你的属性具有retain属性)、释放旧值等。

如果你只是这样做:

aString = someValue;

...您可能会泄漏 in 中的原始值aString,因为不使用self.aString您是直接访问变量而不是通过属性访问变量。

于 2011-06-15T15:30:57.423 回答
12

self->varName注意和之间的区别self.varName

首先是指针访问。二是财产准入。

为什么这很重要?指针访问是直接的。另一方面,属性访问使用 getter 和 setter(无论是否@synthesized)。此外,为方便起见,@synthesized 访问器会为您处理内存管理(即在使用时self.varName = ...;),而varName = ...;只执行它所说的,即赋值 ->(您可能会遇到 EXC_BAD_ACCESS 错误的解释)。

从语法上讲,这两种形式都是正确的。如果您想更好地传达意图,self->varName请在您想直接使用指针工作时使用,并self.varName在您想利用@property便利时使用。

于 2011-06-15T15:46:15.603 回答
7

aString以下是所有可能的组合(我认为)只有当属性具有属性时,OK 和 BAD 才是正确的retain

@property (nonatomic, retain) NSMutableString *aString;

所以:

1

aString = [[NSMutableString alloc] init]; //OK: 

这没关系,但仅在 aString 没有指向无效对象的情况下,或者您将丢失对该对象的引用并且它会泄漏,因为您将无法到达它以释放它。

2

aString = [NSMutableString string]; //BAD

不好,因为您应该保留 aString (正如您以这种方式声明的那样),您没有保留它,并且将来您肯定会得到 EXC_BAD_ACCESS

3

aString = [[NSMutableString string] retain]; //OK

与第一种方法相同,仅当 aString 未指向有效对象时才有效。不过我会使用第一个。

4

aString = [[[NSMutableString alloc] init] autorelease];//BAD

与第二种方法相同。

5

self.aString = [[NSMutableString alloc] init]; //BAD!!

不好,因为您要保留它两次,因此会导致内存泄漏

6

self.aString = [[NSMutableString string]; //******GOOD!******

这可能是最安全的。它将由属性设置器保留,并且由于您正在使用设置器,因此 aString 可能已指向的任何其他对象都将被适当地释放

7

self.aString = [[NSMutableString string] retain]; //BAD

这被保留了两次。

8

self.aString = [[[NSMutableString alloc] init] autorelease];//Ok

这也可以,但我会使用方便的方法而不是这种冗长的方法:)

如果您知道自己在做什么,请注意#1 和#3 选项非常好。事实上,我比#6 更频繁地使用它们

于 2011-06-15T15:34:40.097 回答
2

我个人更喜欢使用self.语法。它只是更容易确定它是一个实例变量,而不仅仅是当前范围内的一些其他变量,当它的 NSAutoreleasePool 耗尽时,这些变量将丢失。但是,两种方式都使用它们是正确的,如果您收到 EXC_BAD_ACCESS 错误,这并不是因为您没有使用self.. 你说你必须分配它是正确的,无论你选择哪种方式访问​​你的变量,都要保持一致,否则你会收到错误。

我希望这有帮助。

于 2011-06-15T15:30:32.120 回答
2

始终使用除 ininitdeallocin 访问器本身之外的访问器。这样做会为您省去很多麻烦,就像您所描述的那样。此外,将您的 ivars 命名为与您的属性不同的名称(_foo, foo_, mFoo,但不是foo)。

self.foo与 完全相同[self foo]。我调用方法fooself.foo = x是完全一样的[self setFoo:x]。它调用方法setFoo:。如果您将属性合成fooretain变量,则如下所示:

@synthesize foo = foo_;

- (void)setFoo:(id)value {
  [value retain];
  [foo_ release];
  foo_ = value;
}

这会正确释放 的旧值foo_,分配一个新值并保留它。

foo = x(假设foo是 ivar)不调用任何方法。没有任何。它只是将指针 in 的值分配给 inx的指针foo。如果foo指向被保留的东西,它就会被泄露。如果您分配的新值未保留,您将在以后崩溃。

解决方案是尽可能使用访问器。

于 2011-06-15T15:38:51.220 回答
1

任何一个。

使用点语法(对某些人来说)更简洁,并且可以编译为等效的。ieself.iVar是一样的[self iVar]并且self.iVar = aValue是一样的[self setIVar:aValue];

于 2011-06-15T15:26:04.963 回答
0

self.aString是 . 的语法糖[self aString]。合成一个属性只需创建-aStringand-setAString:方法(取决于您选择的属性,而不是微不足道的做作)。

现在的问题是是否使用该.符号。我建议你不要使用它。为什么?首先要知道 Objective-C 的目标只是对 C 的补充。这意味着每个有效的 C 代码也是有效的 Objective-C 代码。

现在看看他们用点符号做了什么。最后一条语句不再成立。您不会区分访问 C 结构的字段和发送 Objective-C 方法。

所以请不要使用点符号。更喜欢使用 [self ..]。

于 2011-06-15T15:45:32.343 回答