2010-04-30 87 views
2

我有一个按钮,用户点击开始录制,然后再次点击停止。当它停止时,我想要录制的语音“回声”回来,以便用户可以听到所录制的内容。这是第一次正常工作。如果我第三次按下按钮,它会开始一个新的录音,当我停下来时,它会与EXC_BAD_ACCESS一起崩溃。AVAudioPlayer从AVAudioRecorder播放后崩溃

- (IBAction) readToMeTapped { 

     if(recording) 

     { 
     recording = NO; 
     [readToMeButton setTitle:@"Stop Recording" forState: UIControlStateNormal ];  

     NSMutableDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys: 
     [NSNumber numberWithFloat: 44100.0],     AVSampleRateKey, 
     [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey, 
     [NSNumber numberWithInt: 1],       AVNumberOfChannelsKey, 
     [NSNumber numberWithInt: AVAudioQualityMax],   AVEncoderAudioQualityKey, 
     nil]; 

     // Create a new dated file 
     NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0]; 
     NSString *caldate = [now description];   
     recordedTmpFile = [NSURL fileURLWithPath:[[NSString stringWithFormat:@"%@/%@.caf", DOCUMENTS_FOLDER, caldate] retain]]; 
     error = nil; 
     recorder = [[ AVAudioRecorder alloc] initWithURL:recordedTmpFile settings:recordSetting error:&error]; 
     [recordSetting release]; 
     if(!recorder){ 
      NSLog(@"recorder: %@ %d %@", [error domain], [error code], [[error userInfo] description]); 
      UIAlertView *alert = 
      [[UIAlertView alloc] initWithTitle: @"Warning" 
             message: [error localizedDescription] 
             delegate: nil 
          cancelButtonTitle:@"OK" 
          otherButtonTitles:nil]; 
      [alert show]; 
      [alert release]; 
      return; 
     } 


     NSLog(@"Using File called: %@",recordedTmpFile); 
     //Setup the recorder to use this file and record to it. 

     [recorder setDelegate:self]; 
     [recorder prepareToRecord]; 

     [recorder recordForDuration:(NSTimeInterval) 5]; //recording for a limited time 

    } 
    else 
    { // it crashes the second time it gets here! 
     recording = YES;    
     NSLog(@"Recording YES Using File called: %@",recordedTmpFile); 
     [readToMeButton setTitle:@"Start Recording" forState:UIControlStateNormal ]; 

     [recorder stop]; //Stop the recorder. 

     //playback recording 
     AVAudioPlayer * newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:recordedTmpFile error:&error]; 
     [recordedTmpFile release]; 

     self.aPlayer = newPlayer; 
     [newPlayer release]; 

     [aPlayer setDelegate:self]; 
     [aPlayer prepareToPlay]; 
     [aPlayer play]; 
     } 
} 

- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)sender successfully:(BOOL)flag { 

     NSLog (@"audioRecorderDidFinishRecording:successfully:"); 

     [recorder release]; 
     recorder = nil; 
} 

检查调试器,它标志了这里

@synthesize aPlayer, recorder; 

错误这是我不理解的部分。我认为这可能与释放记忆有关,但我一直很小心。我错过了什么吗?

+0

您对多线程编程有多熟悉? – lucius 2010-04-30 07:23:11

回答

0

您是否确定@property (retain)不包含非原子?我在想一些访问这些属性的代码可能会从另一个线程中这样做。此外,您应该始终使用self.recorder和self.player通过其getter访问这些属性,以确保它们在各自的锁中被访问。

+0

嗨Lucius,我试过你的建议,那不是问题。见下文。 – munchine 2010-04-30 21:22:16

1

经过一段时间的工作后,我偶然发现了debugging tip。它告诉我AVAudioPlayer第二次被释放,导致崩溃。所以代表必须完成清理工作?我检查了这个SO线程,并建议Delegate不要释放。但是,如果我删除该行

[newPlayer release]; 

我的程序可行!在看完这个SO线程之后,我相信我的问题是我应该实现AVAudioPlayerDelegate's - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag方法并在声音播放完成后在那里释放音频播放器。我已经为AVAudioRecorder做过了。