AVAudioPlayer始终是nill,其isPlaying属性始终为false。播放时文件混合在一起 [英] AVAudioPlayer is always nill and its isPlaying property is always false. The files are mixed while playing
问题描述
三天后我一直拔出头发来解决这个问题。我已经检查了大量的示例代码,阅读了大量的教程,并使用Google搜索并检查了很多关于stackoverflow的问题和答案,但我仍然无法解决问题。有几个类似的问题,如这个或这个但他们也没有任何解决方案。
I've been pulling out my hair past three days to fix this problem. I've checked lots of sample codes, read lots of tutorials, and googled and checked lots and lots of questions and answers on stackoverflow, but I still cannot fix the problem. There are several similar questions like this or this but they don't have any solutions either.
关于我的项目的一点点:
So a little bit about my project:
我有一个 NIKMasterViewController
和一个 NIKDetailViewController
。在第一个中,我在表格视图中有一个音频文件列表;选择一行,它导航到 NIKDetailViewController
,用户可以在其中查看有关该文件的一些信息并播放音频文件。
我在 NIKMasterViewController
中定义了一个 AVAudioPlayer
属性,并设置如下:
NIKMasterViewController.h
:
I have a NIKMasterViewController
and a NIKDetailViewController
. In the first one I have a list of audio files in a table view; selecting a row, it navigates to the NIKDetailViewController
where the user can see some info about the file and play the audio file.
I've defined an AVAudioPlayer
property in the NIKMasterViewController
and have set it like this:
NIKMasterViewController.h
:
@property(非原子,强)AVAudioPlayer * audioPlayer;
NIKMasterViewController.m
:
@synthesize audioPlayer;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showDetail"])
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NIKDetailViewController *detailViewController = (NIKDetailViewController *) segue.destinationViewController;
[detailViewController setAudioPlayer:audioPlayer];
[detailViewController setFeedEntry:[[[self feedParser] feedItems] objectAtIndex:indexPath.row]];
} else {
NSLog(@"Segue Identifier: %@", segue.identifier);
}
}
这就是 AVAudioPlayer
在 NIKMasterViewController
中。现在在我的 NIKDetailViewController
我有另一个属性 AVAudioPlayer
:
And that's all about the AVAudioPlayer
in NIKMasterViewController
. Now in my NIKDetailViewController
I have another property of AVAudioPlayer
:
NIKDetailViewController.h
:
@property(非原子,强)AVAudioPlayer * audioPlayer ;
现在我的.m文件中有一个名为 streamAudio
的方法,这是在 viewDidLoad
中调用以准备音频播放,我有 if
条件要求检查 audioPlayer
是 nill
如果没有,如果 audioPlayer.isPlaying
为真,那么它停止
s播放器,但它从未被调用,当我导航回主VC以点击另一行播放另一个文件时,第二个文件开始播放第一个文件正在播放,所有内容都混淆了。
Now in my .m file I have a method called streamAudio
which is called in viewDidLoad
to prepare the audio playback, and I have an if
condition asking to check if the audioPlayer
is nill
and if not, if the audioPlayer.isPlaying
is true so that it stop
s the player, but it's never called, and when i navigate back to the Master VC to tap on another row to play another file, the second file starts playing while the first file is being played and everything gets mixed up.
任何帮助都会得到真正的赞赏,因为我几乎要在无法修复此问题后停止编程下班后和几天!
Any help will be truly appreciated, since I'm almost about to stop programming after being unable to fix this issue after hours and days!
NIKDetailViewController.m
:
@synthesize audioPlayer;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
selectedItem = [[NSString alloc]init];
}
return self;
}
#pragma mark - Managing the Audio Playback
- (IBAction)togglePlayingState:(id)button
{
//Handle the button pressing
[self togglePlayPause];
}
- (void)playAudio
{
//Play the audio and set the button to represent the audio is playing
[audioPlayer play];
[playPauseButton setImage:[UIImage imageNamed:@"player_pause"] forState:UIControlStateNormal];
}
- (void)pauseAudio
{
//Pause the audio and set the button to represent the audio is paused
[audioPlayer pause];
[playPauseButton setImage:[UIImage imageNamed:@"player_play"] forState:UIControlStateNormal];
}
- (void)togglePlayPause
{
//Toggle if the music is playing or paused
if (!audioPlayer.playing)
{
[self playAudio];
}
else if (audioPlayer.playing)
{
[self pauseAudio];
}
}
- (void)streamAudio
{
currentFileName = [[feedEntry podcastDownloadURL] lastPathComponent];
NSString* documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* path = [documentPath stringByAppendingPathComponent:currentFileName];
NSURL* audioURL = [NSURL fileURLWithPath: path];
if (audioPlayer != nil)
{
if (audioPlayer.isPlaying)
{
[audioPlayer stop]; //THIS IS NEVER CALLED
}
audioPlayer = nil; //THIS IS NEVER CALLED
}
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
// Set a timer which keep getting the current music time and update the UISlider in 1 sec interval
playbackTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateSlider) userInfo:nil repeats:YES];
// Set the maximum value of the UISlider
seekSlider.maximumValue = audioPlayer.duration;
currentTime.text = [NSString stringWithFormat:@"%d:%02d", (int)audioPlayer.currentTime / 60, (int)audioPlayer.currentTime % 60, nil];
remainingTime.text = [NSString stringWithFormat:@"%d:%02d", (int)(audioPlayer.duration - audioPlayer.currentTime) / 60, (int)(audioPlayer.duration - audioPlayer.currentTime) % 60, nil];
// Set the valueChanged target
[seekSlider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
audioPlayer.delegate = self;
[audioPlayer prepareToPlay]; //Add the audio to the memory.
}
- (void)updateSlider
{
// Update the slider about the music time
seekSlider.value = audioPlayer.currentTime;
}
- (IBAction)sliderChanged:(UISlider *)sender {
// Fast skip the music when user scrolls the slider
[audioPlayer stop];
[audioPlayer setCurrentTime:seekSlider.value];
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer play];
}
// Stop the timer when the music is finished (Need to implement the AVAudioPlayerDelegate in the Controller header)
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
// Music completed
if (flag) {
[playbackTimer invalidate];
}
}
- (IBAction)forwardAudio:(id)sender
{
int currentTime = [audioPlayer currentTime];
[audioPlayer setCurrentTime:currentTime+10];
}
- (IBAction)rewindAudio:(id)sender
{
int currentTime = [audioPlayer currentTime];
[audioPlayer setCurrentTime:currentTime-10];
}
//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl) {
if (event.subtype == UIEventSubtypeRemoteControlPlay) {
[self playAudio];
} else if (event.subtype == UIEventSubtypeRemoteControlPause) {
[self pauseAudio];
} else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
[self togglePlayPause];
}
}
}
#pragma mark - view life cycle
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//Once the view has loaded then we can register to begin recieving controls and we can become the first responder
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//End recieving events
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self streamAudio];
//Make sure the system follows our playback status - to support the playback when the app enters the background mode.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
注意:我我已经尝试将详细VC中的属性设置为弱
但是,我收到警告,并且该属性在我播放文件之前就已释放。
NOTE: I have tried setting the property in the Detail VC as weak
but then, I get a warning, and the property is release before I can play the file.
推荐答案
所以...我终于可以通过创建单身
来解决这个问题C $ C> audioplayer 。这是如何:
So... I could finally fix this problem by creating a singleton
of the audioplayer
. This is how:
- 首先,我删除了与
audioPlayer $ c $相关的所有代码c>来自我的
NIKMasterViewController
类,其中包含audioPlayer
声明并将其设置为prepareForSegue
。 - 我创建了一个名为
NIKAudioPlayer
的新类。 -
In
NIKAudioPlayer.h
:
- First of all, I removed all the code related to the
audioPlayer
from myNIKMasterViewController
class, that includes theaudioPlayer
declaration and setting it inprepareForSegue
. - I created a new class called
NIKAudioPlayer
. In
NIKAudioPlayer.h
:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
@interface NIKAudioPlayer : NSObject <AVAudioPlayerDelegate>
{
AVAudioPlayer *currentPlayer;
}
@property (nonatomic, strong) AVAudioPlayer *currentPlayer;
+(NIKAudioPlayer *) sharedPlayer;
-(void)playURL:(NSURL*)url;
@end
在 NIKAudioPlayer.m
:
#import "NIKAudioPlayer.h"
@implementation NIKAudioPlayer
@synthesize currentPlayer;
+(NIKAudioPlayer *) sharedPlayer
{
static NIKAudioPlayer* sharedPlayer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPlayer = [[NIKAudioPlayer alloc] init];
});
return sharedPlayer;
}
-(void)playURL:(NSURL*)url
{
[currentPlayer stop];
currentPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[currentPlayer prepareToPlay];
}
@end
现在到处都是在我需要播放音频文件的代码中(在我的情况下在 NIKDetailViewController
中),我调用 sharedPlayer
来自 NIKAudioPlayer
:
[[NIKPlayer sharedPlayer] playURL:audioURL];
[[NIKPlayer sharedPlayer].currentPlayer prepareToPlay];
简而言之,全部替换 audioPlayer
在 NIKDetailViewController
中,带 [NIKPlayer sharedPlayer] .currentPlayer
,甚至投下它并在任何地方使用它:
To put in a nutshell, replace all audioPlayer
s in NIKDetailViewController
with [NIKPlayer sharedPlayer].currentPlayer
, or even cast it and use it everywhere:
audioPlayer = [NIKPlayer sharedPlayer] .currentPlayer
这篇关于AVAudioPlayer始终是nill,其isPlaying属性始终为false。播放时文件混合在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!