在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学习正确的语法,因为我更喜欢正确而不是草率。
答案 0 :(得分:13)
如果您在.m文件中声明了一个属性并@synthesize
,则只需将其设置为:
self.aString = @"hi"; // or [[NSMutableString alloc] initWithString:@"hi"];
使用self.varName
利用您的属性声明实际执行的操作 - 它会处理新值的保留(因为您的属性具有retain
属性),为您释放旧值等。< / p>
如果您这样做:
aString = someValue;
...您可能会泄漏aString
中的原始值,因为不使用self.aString
您直接通过该属性访问变量。
答案 1 :(得分:8)
请注意self->varName
和self.varName
第一个是指针访问。第二个是属性访问。
为什么这很重要?指针访问是直接的。另一方面,属性访问使用getter和setter(不管是@synthesized
还是self.varName = ...;
)。此外,为了方便起见,@synthesized访问器为您处理内存管理(即使用varName = ...;
时),而self->varName
仅执行它所说的内容,即赋值 - &gt; (这可能是您可能遇到的EXC_BAD_ACCESS错误的解释)。
从语法上讲,两种形式都是正确的。如果您想更好地传达意图,请在需要直接使用指针时使用self.varName
,并在想要利用@property
便利时使用{{1}}。
答案 2 :(得分:7)
以下是所有可能的组合(我认为)
只有aString
属性具有retain
属性
@property (nonatomic, retain) NSMutableString *aString;
所以:
aString = [[NSMutableString alloc] init]; //OK:
这没关系,但只有在aString没有指向无效对象的情况下,否则您将丢失对该对象的引用,并且它将泄漏,因为您将无法访问它以释放它。
aString = [NSMutableString string]; //BAD
错误,因为你假设保留一个字符串(正如你所声明的那样),你没有保留它,你将来肯定会得到EXC_BAD_ACCESS
aString = [[NSMutableString string] retain]; //OK
与第一种方法相同,只有当aString没有指向有效对象时才有用。但是我会使用第一个。
aString = [[[NSMutableString alloc] init] autorelease];//BAD
与第二种方法相同。
self.aString = [[NSMutableString alloc] init]; //BAD!!
糟糕,因为你保留了两次,因此会导致内存泄漏
self.aString = [[NSMutableString string]; //******GOOD!******
这可能是最安全的。它将由属性设置器保留,因为您正在使用setter,任何其他可能由aString指向的对象都将被正确释放
self.aString = [[NSMutableString string] retain]; //BAD
保留两次。
self.aString = [[[NSMutableString alloc] init] autorelease];//Ok
这也没关系,但我会使用方便方法而不是这个长方法:)
如果您知道自己在做什么,请注意#1和#3选项非常好。事实上,我比#6更频繁地使用它们
答案 3 :(得分:2)
我个人更喜欢使用self.
语法。它只是更容易确定它是一个实例变量,而不仅仅是当前范围中的一些其他变量,当它的NSAutoreleasePool被耗尽时将会丢失。但是,以两种方式使用它们是正确的,如果您收到EXC_BAD_ACCESS错误,则不是因为您在不使用self.
的情况下访问它。你说你必须分配它,以及你选择访问变量的方式,保持一致或者你会收到错误,这是正确的。
我希望这会有所帮助。
答案 4 :(得分:2)
始终使用除init
,dealloc
以及访问者本身之外的访问者。这样做可以为您节省很多麻烦,比如您所描述的那些。另外,将您的ivars命名为与您的财产不同的地方(_foo
,foo_
,mFoo
,但不是foo
。)
self.foo
与[self foo]
完全相同。我调用方法foo
。 self.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 ..]。