由于我对OOP世界相对较新,我想知道通过不断向物业分配东西可能造成的混乱。
我有一个属性:
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;
然后在我的viewcontroller.m文件中合成。 现在,我有一个方法来初始化audioPlayer,为它设置一个URL等。令我担心的是,每次选择新声音时我都会调用此初始化方法(允许用户从拾取器播放声音):
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
上面的代码显示了每次更改选择器值时调用的行。
在我喋喋不休之前,以上几行a)每次调用它时都会创建一个AVAudioPlayer对象的新实例,或者b)仅仅“覆盖”现有的audioPlayer实例? 如果a),我怀疑我可以很快地杀死记忆;我该怎么做才能让它高效? 如果b),我猜那没关系呢? ......如果秘密回答c)(你完全误解了对象是如何被创造的),那么请为我的无知发光。
谢谢!
答案 0 :(得分:3)
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
应该是:
self.audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil] autorelease];
或
AVAudioPlayer *aPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
self.audioPlayer = aPlayer;
[aPlayer release];
为了清晰起见,添加了一些细节。
我认为令人困惑的部分是self.audioPlayer对吗?将它视为一种方法可能会有所帮助,这实际上就是一个setter。
这些行是等效的:
self.audioPlayer = aPlayer;
[self setAudioPlayer:aPlayer];
由于该属性设置为“retain”,因此方法setAudioPlayer内置了[aPlayer retain]行。因此,如果您不释放aPlayer的本地副本,则会保留两次。
希望有所帮助。
答案 1 :(得分:1)
每次调用alloc时,都会创建一个新的对象实例。但是,具有“retain”属性的属性将采用先前存储的值并在其上调用release。
因此,对于您的引用计数,alloc / init = +1和release = -1。您需要做的是担心减少完成后创建的最后一个副本。
答案 2 :(得分:1)
在分配新分配的对象时,应避免使用属性。例如,如果您的audioPlayer属性被合成以读取和写入名为mAudioPlayer的成员变量,那么您应该这样做:
mAudioPlayer = [[AVAudioPlayer] alloc] initWithContentsOfURL:fileURL error:nil]
如果你必须使用该属性(因为副作用),那么试试这个:
AVAudioPlayer* audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
self.audioPlayer = audioPlayer;
[audioPlayer release];
这是安全的,因为该属性会自动保留新创建的对象,以便您可以在本地释放它。因此,如果按照您提到的方式进行操作,则会发生泄漏。您的引用为2(来自alloc的1个,保留它的属性中的1个)。如果将self.audioPlayer设置为0或其他实例,则只需将其释放一次。
希望有所帮助。
答案 3 :(得分:1)
这是c)
问题是,每次调用 alloc 时,创建的对象的保留计数增加到1.现在,当您使用 self指定它时。并考虑到你已将该财产宣布为
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;
保留计数增加到2。
当您将另一个对象分配给变量audioplayer时,旧实例的保留计数会减少1.因此旧对象只会泄漏。
您需要的是
self.audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil] autorelease];
如果您在dealloc方法中添加了对audioplayer的发布调用。