访问实例variables的语法? (目标C)
在Objective-C中访问实例variables的正确语法是什么?
假设我们有这个variables:
@interface thisInterface : UIViewController { NSMutableString *aString; } @property (nonatomic, retain) NSMutableString *aString;
而且它是合成的。
当我们想要访问它时,我们首先要分配并初始化它。 在Objective-C编程了大约一个月之后,我看到了两种不同的语法forms。 我已经看到人们只是简单的aString = [[NSMutableString alloc] initWithString:@"hi"]
,他们在那里分配string; 我也看到人们用self.aString
开始,然后他们开始初始化他们的伊娃。 我想我只是想弄清楚什么是初始化一个实例variables的最合适的方式,因为在前面的例子中,我收到了EXC_BAD_ACCESS错误。 在预先self.
虽然,它并没有出现。
原谅我,如果这是一个重复的问题,但在阅读了一些post后,这让我好奇。 我正在尝试使用Objective-C来学习正确的语法,因为我更喜欢正确而不是马虎。
如果你已经声明了一个属性,然后在.m文件中把它合成,你可以像下面这样设置它:
self.aString = @"hi"; // or [[NSMutableString alloc] initWithString:@"hi"];
使用self.varName
可以充分利用你的属性声明实际上做的事 – 它处理新值的retain
(因为你的属性有retain
属性),为你释放旧值等等。
如果你只是这样做:
aString = someValue;
…你可能正在泄漏aString
的原始值,因为没有使用self.aString
你直接访问variables而self.aString
通过属性。
请注意self->varName
和self.varName
之间的区别
首先是指针访问。 第二个是财产访问。
为什么这很重要? 指针访问是直接的。 另一方面,财产访问使用getter和setter( @synthesized
他们是否被@synthesized
)。 此外,作为一个方便,@synthesized访问器照顾你的内存pipe理(即当使用self.varName = ...;
),而varName = ...;
只做它所说的,即赋值 – >(这里有你可能得到的EXC_BAD_ACCESS错误的解释)。
在句法上,两种forms都是正确的。 如果你想更好地交stream意图,当你想直接使用指针时使用self.varName
self->varName
当你想利用self.varName
时使用self.varName
。
这里有所有可能的组合(我认为)当aString
属性具有retain
属性时,OK和BAD才是正确的:
@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
与第二种方法相同。
五
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的select是非常好的。 实际上我比#6更频繁地使用它们
我个人更喜欢使用self.
句法。 它只是让它更容易确定它的一个实例variables,而不是当前作用域中的NSAutoreleasePool被耗尽时将会丢失的其他variables。 但是,使用这两种方法是正确的,如果您收到EXC_BAD_ACCESS错误,则不是因为您在不使用self.
情况下访问它self.
。 你说的是正确的,你必须分配它,无论你select访问variables,保持一致,否则你会收到错误。
我希望这有帮助。
除init
, dealloc
和访问器本身之外,始终使用访问器。 这样做会为您节省很多像您所描述的头痛。 另外,将你的ivars命名为不同于你的属性( _foo
, foo_
, mFoo
,但不是foo
)。
self.foo
与[self foo]
完全相同。 我把这个方法叫做foo
。 self.foo = x
与[self setFoo:x]
。 它调用方法setFoo:
如果将foo
属性合成为retain
variables,那么这看起来像这样:
@synthesize foo = foo_; - (void)setFoo:(id)value { [value retain]; [foo_ release]; foo_ = value; }
这正确地释放foo_
的旧值,分配一个新值并保留它。
foo = x
(假设foo
是一个ivar)不会调用任何方法。 没有。 它只是将x
中指针的值赋给foo
的指针。 如果foo
指出某些被保留的东西,它会被泄漏。 如果您分配的新值没有保留,则稍后会崩溃。
解决这个问题的方法是在任何时候总是使用访问器。
无论是。
使用点语法更清晰(对一些),它编译为等效。 即self.iVar
与[self iVar]
相同, self.iVar = aValue
与[self setIVar:aValue];
self.aString
是[self aString]
一个语法糖。 合成属性只需创build-aString
和-setAString:
方法(取决于您select的属性,而不是微不足道的作用)。
现在的问题是是否使用.
符号。 我build议你不要使用它。 为什么? 首先知道Objective-C只是C的一个附加。这意味着每个有效的C代码也是一个有效的Objective-C代码。
现在看看他们用点符号做了什么。 最后的声明不再成立。 你不会区分对C结构域的访问和发送objective-c方法。
所以请不要使用点符号。 更喜欢使用[self ..]。