Reputation: 3541
I have a series of short (1 second) sound clips I need to play in succession. A class is being developed for this purpose. I'm using the following code:
- (void) playClip: (NSData *)clipToPlay
{
NSError *error = nil;
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithData: clipToPlay error:&error];
audioPlayer.numberOfLoops = 0;
audioPlayer.volume = 1.0f;
[audioPlayer prepareToPlay];
if (audioPlayer == nil)
NSLog(@"%@", [error description]);
else
[audioPlayer play];
}
As can be seen, clipToPlay
contains a sound clip as NSData
. The behavior of this code is strange. If I'm running it in the debugger and set the breakpoint at the following line:
[audioPlayer play];
The clip plays as expected -- the debugger pauses on the line, when you step through the line, the clip plays perfectly. If, however, I take the breakpoint out, it doesn't play at all.
I've tried copying the NSData
to a scratch file first, with precisely the same result. I've also copied clipToPlay
to another variable (using a copy, not just a pointer assignment) with identical results (I was thinking perhaps clipToPlay was getting clobbered somewhere). I'm not getting an error logged.
I'm really stuck on why pausing the debugger on the play method would cause this to happen like this. Any suggestions or ideas?
Upvotes: 4
Views: 280
Reputation: 3541
Okay, I found this problem so I'll answer my own question so perhaps it will save someone else some time down the road.
The problem was that the AVAudioPlayer was being deallocated before it had a chance to play the sound. When stopped at a breakpoint, there was obviously the opportunity to play the sound before it was deallocated.
In this instance, since it was in its own subclass, I made audioPlayer an ivar AND I made the variable holding the reference to the subclass an ivar in the calling view controller. This prevented deallocation while the sound was unplayed.
In the subclass, I nil the audioPlayer pointer in the delegate method:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
I'm not sure what the final form of this arrangement will be but this at least explained what was causing the problem. The AVAudioPlayer instance has to be in its scope until the sound finishes playing or ARC will deallocate it.
Upvotes: 5