【发布时间】:2015-12-03 10:45:32
【问题描述】:
我正在使用“AVFoundation.h”对音频播放器进行编程。我有更新进度条的问题,因此当我点击播放按钮时,我的应用程序出错。我附上了代码示例和错误报告。谁能解决这个问题?
-(void)updateProgress {
NSInteger durationMinutes = [self.audioPlayer duration] / 60;
NSInteger durationSeconds = [self.audioPlayer duration] - durationMinutes * 60;
NSInteger currentTimeMinutes = [self.audioPlayer currentTime] / 60;
NSInteger currentTimeSeconds = [self.audioPlayer currentTime] - currentTimeMinutes * 60;
NSString *progressString = [NSString stringWithFormat:@"%d:%02d / %d:%02d", currentTimeMinutes, currentTimeSeconds, durationMinutes, durationSeconds];
self.timeLabel.text = progressString;
self.progressBar.progress = [self.audioPlayer currentTime] / [self.audioPlayer duration];
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInt:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInt:durationSeconds];
NSString *songTitle = [self.selectedFilePath lastPathComponent];
NSString *artistName = @"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:@[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:@[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
[infoCenter setNowPlayingInfo:infoDict]; }
当按下 Build & Run 应用程序在模拟器中成功启动时,我拍摄了 2 张活动控制台的图像 1. 在点击播放按钮之前。
- 点击播放按钮后。当应用崩溃时。
现在请建议我此时应该做什么?以便我的应用程序开始顺利运行... 谢谢 法伊兹。
按照 Losiowaty 的说明进行了最后一天的回答。这些黄色问题已被删除,但当我点击播放按钮时,我的编程仍然会出现同样的错误。 enter image description here
这次我上传了完整的代码并突出显示了一些我认为正在发生错误的事情。 请看一下我的 mainwviewcontroller.m 类代码。
@interface MainViewController ()
@end
@implementation MainViewController
@synthesize audioPlayer;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error == nil) {
NSLog(@"audio session initialized successfully");
} else {
NSLog(@"error initializing audio session: %@", [error description]);
}
[audioPlayer setDelegate:self];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;
[volumeView setFrame:self.airPlayView.bounds];
[self.airPlayView addSubview:volumeView];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(caughtInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)canBecomeFirstResponder
{
return YES;
}
-(void)dealloc
{
[self resignFirstResponder];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showFilePicker"]) {
UINavigationController *navigationController = (UINavigationController *)segue.destinationViewController;
FileViewController *fileViewController = (FileViewController *)navigationController.topViewController;
fileViewController.delegate = self;
}
}
#pragma mark - file picker delegate methods
-(void)cancel
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)didFinishWithFile:(NSString *)filePath
{
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.selectedFilePath = filePath;
NSString *relativeFilePath = [documentsDirectory stringByAppendingPathComponent:filePath];
NSURL *fileURL = [NSURL fileURLWithPath:relativeFilePath];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
self.audioPlayer.delegate = self;
if (error == nil) {
NSLog(@"audio player initialized successfully");
self.titleLabel.text = self.selectedFilePath;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
NSString *songTitle = [filePath lastPathComponent];
NSString *artistName = @"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:@[songTitle, artistName, albumArt] forKeys:@[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork]];
[infoCenter setNowPlayingInfo:infoDict];
[self play:nil];
} else {
NSLog(@"error initializing audio player: %@", [error description]);
}
//dismiss the file picker
[self dismissViewControllerAnimated:YES completion:nil];
}
-(IBAction)play:(id)sender
{
if ([self.audioPlayer isPlaying]) {
[self.audioPlayer pause];
[self.playButton setImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal];
[self.timer invalidate];
[animation stopAnimating];
} else {
[self.audioPlayer play];
[self.playButton setImage:[UIImage imageNamed:@"pause"] forState:UIControlStateNormal];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
animation.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:@"animation1.png"],
[UIImage imageNamed:@"animation2.png"],
[UIImage imageNamed:@"animation3.png"],nil];
[animation setAnimationRepeatCount:2000];
animation.animationDuration = 0.5;
[animation startAnimating];
}
self.playbackInterrupted = NO;
}
-(IBAction)skipForward:(id)sender
{
if ([self.audioPlayer isPlaying]) {
NSTimeInterval desiredTime = self.audioPlayer.currentTime + 15.0f;
if (desiredTime < self.audioPlayer.duration) {
self.audioPlayer.currentTime = desiredTime;
}
}
}
-(IBAction)skipBackward:(id)sender
{
if ([self.audioPlayer isPlaying]) {
NSTimeInterval desiredTime = self.audioPlayer.currentTime - 15.0f;
if (desiredTime < 0) {
self.audioPlayer.currentTime = 0.0f;
} else {
self.audioPlayer.currentTime = desiredTime;
}
}
}
#pragma mark - Timer delegate
-(void)updateProgress
{
NSInteger durationMinutes = [self.audioPlayer duration] / 60;
NSInteger durationSeconds = [self.audioPlayer duration] - durationMinutes * 60;
NSInteger currentTimeMinutes = [self.audioPlayer currentTime] / 60;
NSInteger currentTimeSeconds = [self.audioPlayer currentTime] - currentTimeMinutes * 60;
NSString *progressString = [NSString stringWithFormat:@"%ld:%02ld / %ld:%02ld", currentTimeMinutes,currentTimeSeconds, durationMinutes, durationSeconds];
self.timeLabel.text = progressString;
self.progressBar.progress = [self.audioPlayer currentTime] / [self.audioPlayer duration];
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInteger:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInteger:durationSeconds];
NSString *songTitle = [self.selectedFilePath lastPathComponent];
NSString *artistName = @"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:@[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:@[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
[infoCenter setNowPlayingInfo:infoDict];
}
#pragma mark - AVAudioPlayer delegate methods
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
if (flag) {
[self.playButton setImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal];
[self.timer invalidate];
[animation stopAnimating];
}
}
#pragma mark - Remote control
-(void)remoteControlReceivedWithEvent:(UIEvent *)event
{
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
case UIEventSubtypeRemoteControlPause:
case UIEventSubtypeRemoteControlTogglePlayPause:
[self play:nil];
break;
case UIEventSubtypeRemoteControlNextTrack:
[self skipForward:nil];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self skipBackward:nil];
break;
default:
break;
}
}
#pragma mark - audio interruption
-(void)caughtInterruption:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSNumber *type =[userInfo objectForKey:AVAudioSessionInterruptionTypeKey];
if ([type integerValue] == AVAudioSessionInterruptionTypeBegan) {
if (self.audioPlayer.playing) {
[self.audioPlayer pause];
[animation stopAnimating];
self.playbackInterrupted = YES;
}
} else {
if (self.audioPlayer.playing == NO && self.playbackInterrupted == YES) {
[self.audioPlayer play];
[animation startAnimating];
self.playbackInterrupted = NO;
}
}
}
#pragma mark - route changed
-(void)routeChanged:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSNumber *reason =[userInfo objectForKey:AVAudioSessionRouteChangeReasonKey];
switch ([reason integerValue]) {
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
[self.audioPlayer stop];
[animation stopAnimating];
break;
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
case AVAudioSessionRouteChangeReasonWakeFromSleep:
[self.audioPlayer pause];
[animation stopAnimating];
break;
default:
break;
}
}
@end
上面的代码没有错误而且很干净,所有的东西都清楚地提到了,我使用了 4 个按钮,
播放和暂停
向前搜索
向后搜索
进入文件目录进行音频文件挑选
当我按下第四个按钮时,它准备进入另一个视图以选择音频文件。
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showFilePicker"]) {
UINavigationController *navigationController = (UINavigationController *)segue.destinationViewController;
FileViewController *fileViewController = (FileViewController *)navigationController.topViewController;
fileViewController.delegate = self;
}
}
我需要完成两件事
我需要完成的第一件事是,
-
我不想进入下一个视图,因为我正在将我的应用程序测试到模拟器中,其中没有我可以在模拟器中放置或定位的物理音频文件,因此我需要避免这件事只是为了我自己的测试目的. 因此,我愿意将音频 mp3 文件添加到 NSBundle 中,并希望在按下播放按钮文件开始播放时播放该文件,然后在再次按下时暂停。支付和暂停的代码非常干净,运行良好。但是对于初始化文件路径,我认为我必须通过以下代码替换上面的视图来初始化 viewDidload 方法中的文件路径。
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:@"Nameofflie" ofType:@"mp3"]; NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath]; NSError *error = nil; audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error]; if (error == nil) { NSLog(@"audio session initialized successfully"); } else { NSLog(@"error initializing audio session: %@", [error description]); } [audioPlayer setDelegate:self]; MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ; [volumeView setFrame:self.airPlayView.bounds]; [self.airPlayView addSubview:volumeView]; [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; [self becomeFirstResponder]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(caughtInterruption:) name:AVAudioSessionInterruptionNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChanged:) name:AVAudioSessionRouteChangeNotification object:nil];}
此代码也可以很好地运行和编译,但是在按下播放按钮时会出现同样的错误。所以请建议我在哪里放置以下几行来播放从 NSBudle 放置的 MP3 音乐文件。
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:@"rabne" ofType:@"mp3"];
NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error];
- 这一点与我愿意完成的第一点完全不同。测试成功后,播放该 NSBundle 音频 MP3 文件。
我想再次使用我之前的代码,因为最终用户没有使用我的模拟器,因此对于最终用户,我希望拥有我已经在上面
Mainviewcontroller.m类中完成的相同选项,即用户必须按第四个数字按钮才能访问其设备的文档目录文件路径。这在我的代码中运行良好。但是我想指出或需要解决的问题是,如果有人直接按第一个播放按钮而不按第四个按钮来选择音频文件,则应该出现一个警报视图,并显示一条消息,首先选择一个文件按第四个按钮,然后单击播放按钮。这就是我愿意在我的代码中包含的内容。
【问题讨论】:
-
你能点击黄色三角形并在那里显示警告吗?此外,当您的应用程序崩溃时,在右侧代码下方的窗口中会出现一个堆栈跟踪,其中可以更好地描述异常。能否展开并粘贴异常和堆栈跟踪?
-
感谢您的回复(建议),我已经尝试了很多次,它提供了在第一个问题中进行细微更改的选项,如下所示。 NSString *progressString = [NSString stringWithFormat:@"%ld:02d / %ld:02d", currentTimeMinutes,(long)currentTimeSeconds, (long)durationMinutes, durationSeconds];在同一行发生的另一个问题是“格式字符串未使用数据参数”。 &没有什么可以解决这个问题,&程序仍然给出同样的错误。
-
这个警告仅仅意味着你传递了 4 个数字来格式化字符串,但只使用了其中的两个。这似乎与崩溃无关,因为警告很少这样做,这就是为什么我还从控制台窗口询问堆栈跟踪和异常描述。
-
当我按下播放按钮应用程序停止工作并显示这些错误时,让我添加更多错误报告图像。当我跳过这个过程时,附上所有的图像。
-
如果你看清楚那一行,我会使用所有四个数字。
标签: ios objective-c avfoundation avaudioplayer