ios - AVAudioPlayer 始终为 nill,其 isPlaying 属性始终为 false。播放时文件混合
<p><p>过去三天我一直在拔头发来解决这个问题。我检查了很多示例代码,阅读了很多教程,并在 stackoverflow 上搜索并检查了很多很多问题和答案,但我仍然无法解决问题。有几个类似的问题,如 <a href="https://stackoverflow.com/questions/3119731/avaudioplayer-isplaying-always-return-null" rel="noreferrer noopener nofollow">this</a>或 <a href="https://stackoverflow.com/questions/17807987/multiple-songs-playing-simultaneously-using-avaudioplayer-in-ios" rel="noreferrer noopener nofollow">this</a>但他们也没有任何解决方案。</p>
<p>关于我的项目的一点点:</p>
<p>我有一个 <code>NIKMasterViewController</code> 和一个 <code>NIKDetailViewController</code>。在第一个中,我在表格 View 中有一个音频文件列表;选择一行,它导航到 <code>NIKDetailViewController</code>,用户可以在其中查看有关文件的一些信息并播放音频文件。
我在 <code>NIKMasterViewController</code> 中定义了一个 <code>AVAudioPlayer</code> 属性并将其设置为:
<code>NIKMasterViewController.h</code>:</p>
<p><code>@property (nonatomic, strong) AVAudioPlayer *audioPlayer;</code></p>
<p><code>NIKMasterViewController.m</code>:</p>
<pre><code>@synthesize audioPlayer;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([ isEqualToString:@"showDetail"])
{
NSIndexPath *indexPath = ;
NIKDetailViewController *detailViewController = (NIKDetailViewController *) segue.destinationViewController;
;
feedItems] objectAtIndex:indexPath.row]];
} else {
NSLog(@"Segue Identifier: %@", segue.identifier);
}
}
</code></pre>
<p>这就是 <code>NIKMasterViewController</code> 中的 <code>AVAudioPlayer</code> 的全部内容。现在在我的 <code>NIKDetailViewController</code> 我有 <code>AVAudioPlayer</code> 的另一个属性:</p>
<p><code>NIKDetailViewController.h</code>:</p>
<p><code>@property (nonatomic, strong) AVAudioPlayer *audioPlayer;</code></p>
<p>现在在我的 .m 文件中,我有一个名为 <code>streamAudio</code> 的方法,该方法在 <code>viewDidLoad</code> 中调用以准备音频播放,并且我有一个 <code>if</code> 条件要求检查 <code>audioPlayer</code> 是否为 <code>nill</code>,如果不是,则 <code>audioPlayer.isPlaying</code> 是否为真,以便 <code>stop </code> 是播放器,但它从未被调用,当我导航回 Master VC 以点击另一行播放另一个文件时,第二个文件开始播放,而第一个文件正在播放,一切都搞混了。 </p>
<p>任何帮助都将不胜感激,因为在数小时和数天后无法解决此问题后,我几乎要停止编程了!</p>
<p><code>NIKDetailViewController.m</code>:</p>
<pre><code>@synthesize audioPlayer;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = ;
if (self) {
// Custom initialization
selectedItem = [init];
}
return self;
}
#pragma mark - Managing the Audio Playback
- (IBAction)togglePlayingState:(id)button
{
//Handle the button pressing
;
}
- (void)playAudio
{
//Play the audio and set the button to represent the audio is playing
;
forState:UIControlStateNormal];
}
- (void)pauseAudio
{
//Pause the audio and set the button to represent the audio is paused
;
forState:UIControlStateNormal];
}
- (void)togglePlayPause
{
//Toggle if the music is playing or paused
if (!audioPlayer.playing)
{
;
}
else if (audioPlayer.playing)
{
;
}
}
- (void)streamAudio
{
currentFileName = [ lastPathComponent];
NSString* documentPath = ;
NSString* path = ;
NSURL* audioURL = ;
if (audioPlayer != nil)
{
if (audioPlayer.isPlaying)
{
;//THIS IS NEVER CALLED
}
audioPlayer = nil; //THIS IS NEVER CALLED
}
audioPlayer = [ initWithContentsOfURL:audioURL error:nil];
// Set a timer which keep getting the current music time and update the UISlider in 1 sec interval
playbackTimer = ;
// Set the maximum value of the UISlider
seekSlider.maximumValue = audioPlayer.duration;
currentTime.text = ;
remainingTime.text = ;
// Set the valueChanged target
;
audioPlayer.delegate = self;
; //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.delegate = self;
;
;
}
// 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) {
;
}
}
- (IBAction)forwardAudio:(id)sender
{
int currentTime = ;
;
}
- (IBAction)rewindAudio:(id)sender
{
int currentTime = ;
;
}
//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) {
;
} else if (event.subtype == UIEventSubtypeRemoteControlPause) {
;
} else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
;
}
}
}
#pragma mark - view life cycle
- (void)viewDidAppear:(BOOL)animated {
;
//Once the view has loaded then we can register to begin recieving controls and we can become the first responder
[ beginReceivingRemoteControlEvents];
;
}
- (void)viewWillDisappear:(BOOL)animated {
;
//End recieving events
[ endReceivingRemoteControlEvents];
;
}
- (void)viewDidLoad
{
;
// Do any additional setup after loading the view, typically from a nib.
;
//Make sure the system follows our playback status - to support the playback when the app enters the background mode.
[ setCategory:AVAudioSessionCategoryPlayback error:nil];
[ setActive: YES error: nil];
}
- (void)didReceiveMemoryWarning
{
;
// Dispose of any resources that can be recreated.
}
@end
</code></pre>
<p><strong>注意:</strong>我已尝试将 Detail VC 中的属性设置为 <code>weak</code> 但随后我收到警告,并且在播放文件之前该属性已释放.</p></p>
<br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
<p><p>所以...我终于可以通过创建 <code>audioplayer</code> 的 <code>singleton</code> 来解决这个问题。方法如下:</p>
<ol>
<li>首先,我从我的 <code>NIKMasterViewController</code> 类中删除了所有与 <code>audioPlayer</code> 相关的代码,其中包括 <code>audioPlayer</code> 声明并设置它在 <code>prepareForSegue</code> 中。 </li>
<li>我创建了一个名为 <code>NIKAudioPlayer</code> 的新类。</li>
<li><p>在 <code>NIKAudioPlayer.h</code>:</p>
<pre><code>#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
</code></pre> </li>
<li><p>在 <code>NIKAudioPlayer.m</code>:</p>
<pre><code>#import "NIKAudioPlayer.h"
@implementation NIKAudioPlayer
@synthesize currentPlayer;
+(NIKAudioPlayer *) sharedPlayer
{
static NIKAudioPlayer* sharedPlayer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPlayer = [ init];
});
return sharedPlayer;
}
-(void)playURL:(NSURL*)url
{
;
currentPlayer = [ initWithContentsOfURL:url error:nil];
;
}
@end
</code></pre> </li>
<li><p>现在在代码中的其他任何地方(在我的例子中是 <code>NIKDetailViewController</code>),每当我需要播放音频文件时,我都会从 <code> 调用 <code>sharedPlayer</code> >NIKAudioPlayer</code>:</p>
<pre><code>[ playURL:audioURL];
[.currentPlayer prepareToPlay];
</code></pre> </li>
</ol>
<p>简而言之,将 <code>NIKDetailViewController</code> 中的所有 <code>audioPlayer</code> 替换为 <code>.currentPlayer</code>,甚至将其转换并使用它无处不在:</p>
<p><code>audioPlayer = .currentPlayer</code></p></p>
<p style="font-size: 20px;">关于ios - AVAudioPlayer 始终为 nill,其 isPlaying 属性始终为 false。播放时文件混合,我们在Stack Overflow上找到一个类似的问题:
<a href="https://stackoverflow.com/questions/20164873/" rel="noreferrer noopener nofollow" style="color: red;">
https://stackoverflow.com/questions/20164873/
</a>
</p>
页:
[1]