访问实例变量的语法? (目标C)

时间:2011-06-15 15:22:01

标签: iphone objective-c ios ivar

在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学习正确的语法,因为我更喜欢正确而不是草率。

7 个答案:

答案 0 :(得分:13)

如果您在.m文件中声明了一个属性并@synthesize,则只需将其设置为:

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

使用self.varName利用您的属性声明实际执行的操作 - 它会处理新值的保留(因为您的属性具有retain属性),为您释放旧值等。< / p>

如果您这样做:

aString = someValue;

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

答案 1 :(得分:8)

请注意self->varNameself.varName

之间的区别

第一个是指针访问。第二个是属性访问。

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

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

答案 2 :(得分:7)

以下是所有可能的组合(我认为) 只有aString属性具有retain属性

时,OK和BAD才正确
@property (nonatomic, retain) NSMutableString *aString;

所以:

1

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

这没关系,但只有在aString没有指向无效对象的情况下,否则您将丢失对该对象的引用,并且它将泄漏,因为您将无法访问它以释放它。

2

aString = [NSMutableString string]; //BAD

错误,因为你假设保留一个字符串(正如你所声明的那样),你没有保留它,你将来肯定会得到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!******

这可能是最安全的。它将由属性设置器保留,因为您正在使用setter,任何其他可能由aString指向的对象都将被正确释放

7

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

保留两次。

8

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

这也没关系,但我会使用方便方法而不是这个长方法:)

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

答案 3 :(得分:2)

我个人更喜欢使用self.语法。它只是更容易确定它是一个实例变量,而不仅仅是当前范围中的一些其他变量,当它的NSAutoreleasePool被耗尽时将会丢失。但是,以两种方式使用它们是正确的,如果您收到EXC_BAD_ACCESS错误,则不是因为您在不使用self.的情况下访问它。你说你必须分配它,以及你选择访问变量的方式,保持一致或者你会收到错误,这是正确的。

我希望这会有所帮助。

答案 4 :(得分:2)

始终使用除initdealloc以及访问者本身之外的访问者。这样做可以为您节省很多麻烦,比如您所描述的那些。另外,将您的ivars命名为与您的财产不同的地方(_foofoo_mFoo,但不是foo。)

self.foo[self foo]完全相同。我调用方法fooself.foo = x[self setFoo:x]完全相同。它调用方法setFoo:。如果您将属性foo合成为retain变量,则类似于:

@synthesize foo = foo_;

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

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

foo = x(假设foo是一个ivar)不会调用任何方法。没有。它只是将x中指针的值赋给foo中的指针。如果foo指向保留的内容,则会泄露。如果您保留的新值未保留,则稍后会崩溃。

解决方法是尽可能使用访问者。

答案 5 :(得分:1)

要么。

使用点语法更清晰(对某些人来说)并且它编译为等效语法。即self.iVar[self iVar]相同,self.iVar = aValue[self setIVar:aValue];相同

答案 6 :(得分:0)

self.aString[self aString]的语法糖。合成属性只需创建-aString-setAString:方法(取决于您选择它的属性,而不是琐碎的做法)。

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

现在看看他们用点符号做了些什么。最后一个声明不再适用。您不会区分对C结构字段的访问和发送objective-c方法。

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