AVAudioPlayer перестает играть сразу с ARC

Я пытаюсь воспроизвести MP3 через AVAudioPlayer который я считал довольно простым. К сожалению, это не совсем работает. Вот все, что я сделал:

  • Для тестирования я создал новое приложение для iOS (Single View) в Xcode.
  • Я добавил в проект фреймворк AVFoundation, а также #import <AVFoundation/AVFoundation.h> к ViewController.m

  • Я добавил файл MP3 в папку "Документы" приложения.

  • Я изменил ViewControllersviewDidLoad: к следующему:

Код:

- (void)viewDidLoad
{
    [super viewDidLoad];        

    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];    

    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil];
    audioPlayer.numberOfLoops = 1;

    [audioPlayer play];

    //[NSThread sleepForTimeInterval:20];
}

К сожалению, звук, очевидно, останавливается сразу после начала воспроизведения. Если я раскомментирую sleepForTimeInterval он играет в течение 20 секунд и затем останавливается. Эта проблема возникает только при компиляции с ARC, в противном случае она работает без нареканий.

3 ответа

Решение

Проблема заключается в том, что при компиляции с ARC вам необходимо сохранять ссылку на экземпляры, которые вы хотите поддерживать, поскольку компилятор автоматически исправит "несбалансированный" alloc вставив release звонки (по крайней мере, концептуально, читайте пост в блоге Mikes Ash для более подробной информации). Вы можете решить эту проблему, назначив экземпляр свойству или переменной экземпляра.

В случае Phlibbo код будет преобразован в:

- (void)viewDidLoad
{
    [super viewDidLoad];        
    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];    
    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil];
    audioPlayer.numberOfLoops = 1;
    [audioPlayer play];
    [audioPlayer release]; // inserted by ARC
}

И AVAudioPlayer он немедленно прекратит играть, так как он освобождается, когда не остается ссылки.

Я не использовал ARC сам и только что прочитал об этом кратко. Пожалуйста, прокомментируйте мой ответ, если вы знаете больше об этом, и я обновлю его с дополнительной информацией.

Больше информации ARC:
Переход на заметки о выпуске ARC
LLVM Автоматический подсчет ссылок

Используйте AVAudioPlayer в качестве ивара в заголовочном файле с strong:

@property (strong,nonatomic) AVAudioPlayer *audioPlayer

Если вам нужно одновременно играть несколько AVAudioPlayers, создайте NSMutableDictionary. Установите ключ в качестве имени файла. Удалить из словаря с помощью делегирования обратного вызова следующим образом:

-(void)playSound:(NSString*)soundNum {


    NSString* path = [[NSBundle mainBundle]
                      pathForResource:soundNum ofType:@"m4a"];
    NSURL* url = [NSURL fileURLWithPath:path];

    NSError *error = nil;
    AVAudioPlayer *audioPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];

    audioPlayer.delegate = self;

    if (_dictPlayers == nil)
        _dictPlayers = [NSMutableDictionary dictionary];
    [_dictPlayers setObject:audioPlayer forKey:[[audioPlayer.url path] lastPathComponent]];
    [audioPlayer play];

}

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {        
   [_dictPlayers removeObjectForKey:[[player.url path] lastPathComponent]];
}
Другие вопросы по тегам