- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 pageViewController (UIPageViewController),它有一个 subview Controller (名为 soundPlayer)。声音播放器有静态 AVAudioPLayer *player
在页面之间导航时,我们必须有播放器(单例模式)。所以如果我在页面之间导航而不播放声音,最后从这些 View Controller (导航 Controller )返回,soundPlayer 将被释放。但是当我播放声音并在页面之间导航时,每翻一页,新的 soundPlayer 都不会释放,并且会创建一个新的 soundPlayer !
在每次翻页播放声音之前,只有我们在soundPlayerViewController上,但是当我们每次翻页播放声音时,soundPlayerViewController并没有释放,活体对象增加了。
播放声音之前
播放声音后
忽略我的真实应用程序中的那些泄漏,我没有它们
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
@class AppScrollView;
@interface SoundPlayerViewController : UIViewController <AVAudioPlayerDelegate>{
BOOL paused;
BOOL inBackground;
NSTimer *updateTimer;
UIImage *playBtnBG;
UIImage *pauseBtnBG;
UIImage *bookmarkedBtnBG;
}
@property (weak, nonatomic) IBOutlet UILabel *duration;
@property (weak, nonatomic) IBOutlet UILabel *currentTime;
@property (weak, nonatomic) IBOutlet UISlider *progressBar;
@property (nonatomic, strong) NSTimer *updateTimer;
@property (nonatomic, assign) BOOL inBackground;
@property (weak, nonatomic) IBOutlet UIButton *playButton;
- (IBAction)playButtonPressed:(UIButton *)sender;
- (IBAction)progressSliderMoved:(UISlider *)sender;
- (void)updateViewForPlayerState:(AVAudioPlayer *)player;
- (void)updateViewForPlayerStateInBackground:(AVAudioPlayer *)player;
- (void)updateViewForPlayerInfo:(AVAudioPlayer *)player;
- (void)updateCurrentTimeForPlayer:(AVAudioPlayer *)player;
- (void)registerForBackgroundNotifications;
- (void)updateBookmarkButton;
- (void)stopSoundPlayer;
@end
SoundPlayerViewController.m
#import "SoundPlayerViewController.h"
@interface SoundPlayerViewController ()
- (void)customizeAppearance;
@end
@implementation SoundPlayerViewController
static AVAudioPlayer *soundPlayer;
@synthesize numberFormatter;
@synthesize duration;
@synthesize currentTime;
@synthesize progressBar;
@synthesize updateTimer;
@synthesize inBackground;
@synthesize playButton;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self customizeAppearance];
paused = true;
[self registerForBackgroundNotifications];
NSError *error = nil;
NSString *fileName = @"sample";
NSString *fileType = @"m4a";
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:fileName ofType:fileType];
NSURL *soundURL = [NSURL fileURLWithPath:soundFilePath];
//soundPalyer is Static so there is one for all of instance objects of this class.
if (!soundPlayer) {
soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
if (soundPlayer) {
[self updateViewForPlayerState:soundPlayer];
[self updateViewForPlayerInfo:soundPlayer];
soundPlayer.numberOfLoops = 0;
soundPlayer.delegate = self;
updateTimer = nil;
}
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//if you pause soundPlayer and curl page you will notice soundPlayer won't update so
//I update sound player
[self updateViewForPlayerState:soundPlayer];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self updateViewForPlayerState:soundPlayer];
[super viewWillDisappear:animated];
}
#pragma mark - my custom functions
- (void)customizeAppearance
{
//change slider appearacne
UIImage *minImage = [[UIImage imageNamed:@"sliderMinTrack"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
UIImage *maxImage = [[UIImage imageNamed:@"sliderMaxTrack"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 9)];
UIImage *thumbImage = [UIImage imageNamed:@"sliderThumb"];
[progressBar setMaximumTrackImage:maxImage
forState:UIControlStateNormal];
[progressBar setMinimumTrackImage:minImage
forState:UIControlStateNormal];
[[UISlider appearance] setThumbImage:thumbImage
forState:UIControlStateNormal];
[[UISlider appearance] setThumbImage:thumbImage
forState:UIControlStateHighlighted];
[playButton setImage:playBtnBG forState:UIControlStateNormal];
}
- (void)pausePlaybackForPlayer:(AVAudioPlayer *)player
{
[player pause];
[self updateViewForPlayerState:player];
}
- (void)startPlaybackForPlayer:(AVAudioPlayer *)player
{
//I must add paused = false here, else if I stop playing and bring front the app from background, sound player continue playing.
paused = false;
player.enableRate = YES;
[player prepareToPlay];
[player play];
[self updateViewForPlayerState:player];
}
- (IBAction)playButtonPressed:(UIButton *)sender
{
if (soundPlayer.playing == YES) {
[self pausePlaybackForPlayer:soundPlayer];
//I use this flag to control when the audio should be played
paused = true;
} else {
[self startPlaybackForPlayer:soundPlayer];
}
}
- (IBAction)progressSliderMoved:(UISlider *)sender
{
soundPlayer.currentTime = sender.value;
progressBar.maximumValue = soundPlayer.duration;
[self updateViewForPlayerState:soundPlayer];
}
- (void)stopSoundPlayer
{
if (self.mailPickerIsPresented) {
if ([soundPlayer isPlaying]) {
self.mailPickerhasPausedPlayback = true;
[self pausePlaybackForPlayer:soundPlayer];
}
}
else
{
[soundPlayer stop];
soundPlayer = nil;
}
}
- (void)updateViewForPlayerState:(AVAudioPlayer *)player
{
if (updateTimer)
[updateTimer invalidate];
if (player.playing) {
if(pauseBtnBG)
{
[playButton setImage:((player.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
}
updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(updateCurrentTime) userInfo:player repeats:YES];
} else {
[playButton setImage:((player.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
//I called this function below to set currentTimeLabel=0 after finishig playing
//[self updateCurrentTimeForPlayer:soundPlayer];
updateTimer = nil;
}
}
- (void)updateViewForPlayerStateInBackground:(AVAudioPlayer *)player
{
[self updateCurrentTimeForPlayer:player];
if (player.playing)
{
[playButton setImage:((player.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
}
else
{
[playButton setImage:((player.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
}
}
-(void)updateViewForPlayerInfo:(AVAudioPlayer*)player
{
duration.text = [NSString stringWithFormat:@"%d:%02d",(int)player.duration / 60, (int)player.duration % 60, nil];
progressBar.maximumValue = player.duration;
}
- (void)updateCurrentTime
{
[self updateCurrentTimeForPlayer:soundPlayer];
}
- (void)updateCurrentTimeForPlayer:(AVAudioPlayer *)player
{
currentTime.text = [NSString stringWithFormat:@"%d:%02d", (int)soundPlayer.currentTime / 60, (int)soundPlayer.currentTime % 60, nil];
progressBar.value = player.currentTime;}
#pragma mark background notifications
- (void)registerForBackgroundNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(setInBackgroundFlag)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(clearInBackgroundFlag)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void)setInBackgroundFlag
{
inBackground = true;
[self pausePlaybackForPlayer:soundPlayer];
}
- (void)clearInBackgroundFlag
{
inBackground = false;
//we are checking if palyer was playing, if so, we continue its playing.
if (paused == false) {
[self startPlaybackForPlayer:soundPlayer];
}
}
#pragma mark AVAudioPlayer delegate methods
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{if (flag == NO)
NSLog(@"Playback finished unsuccessfully");
[player setCurrentTime:0.0];
if (inBackground)
{
[self updateViewForPlayerStateInBackground:player];
}
else
{
[self updateViewForPlayerState:player];
}
}
// we will only get these notifications if playback was interrupted
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)p
{
NSLog(@"Interruption begin. Updating UI for new state");
// the object has already been paused, we just need to update UI
if (inBackground)
{
[self updateViewForPlayerStateInBackground:p];
}
else
{
[self updateViewForPlayerState:p];
}
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)p
{
NSLog(@"Interruption ended. Resuming playback");
[self startPlaybackForPlayer:p];
}
@end
我已经上传了示例应用程序
最佳答案
我建议您创建单例来管理您的 AVAudioPlayer,如下所示
界面
// AudioManager.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
@interface AudioManager : NSObject
@property (nonatomic, strong) AVAudioPlayer *soundPlayer;
+ (id)sharedManager;
@end
// AudioManager.m
#import "AudioManager.h"
#define kSoundFileName @"sample.m4a"
实现
@implementation AudioManager
+ (id)sharedManager
{
static AudioManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (AVAudioPlayer *)soundPlayer
{
NSError *error;
if (_soundPlayer == nil)
{
_soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[self soundURL] error:&error];
}
return _soundPlayer;
}
- (NSURL *)soundURL
{
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"bgMusic" ofType:@"mp3"];
return [NSURL fileURLWithPath:soundFilePath];
}
@end
在其他 View Controller 中,您可以在单例对象上引用 AVAudioPlayer 属性,其中只会创建单个 AudioManager 对象,如下所示
#import "AudioManager.h"
[[[AudioManager sharedManager] soundPlayer] play];
关于ios - 播放声音后 childViewController 不释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21062611/
我有一个附加了 View Controller 的 AVAudioPlayer 实例。 @property (nonatomic, retain) AVAudioPlayer *previewAudi
我是java初学者。假设我声明了一个 Account 类型的变量 Account _account = new Account("Thomas"); 然后在其他地方我做了这样的事情: _account
我在我的应用程序中使用了 3 个 UIViewController,现在我想知道当我从另一个应用程序切换到另一个 UIViewController 时释放它们是否是一个好主意。显然,这将是隐藏的,当它
我分配了一个直接缓冲区: ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); 我读过: Deallocating Direct Buf
场景。我有一个图表,我可以使用右键单击来执行平移。这非常有效。然后我完美地添加了右键菜单。 问题。现在,即使在拖动操作完成后释放鼠标,也会显示右键菜单。 有没有办法在 Java Swing 或 Jav
我使用此代码获取 ABPerson 的姓氏 CFStringRef lastNameRef = ABRecordCopyValue((ABRecordRef)personRecordRef, kABP
目前,我们在基于 C 的嵌入式应用程序中使用 malloc/free Linux 命令进行内存分配/取消分配。我听说这会导致内存碎片,因为内存分配/取消分配会导致堆大小增加/减少,从而导致性能下降。其
当我尝试释放缓冲区时遇到问题。每次我尝试将缓冲区传递给释放方法时,都会发生段错误。 Valgrind 确认段错误位于 BufferDeallocate 方法中。 ==30960== Memcheck,
我想知道何时按下或释放修改后的键(Ctrl 或 Shift)。 基本上,用户可以在按下修改键的情况下执行多次击键,而我不想在它被释放之前执行一个操作(想想 Emacs 和 Ctrl + X + S).
我编写了一个相当大的网络应用程序。它运行良好一段时间,然后慢慢开始运行缓慢,因为 DOM 节点开始爬升到 80,000 - 100,000 左右。 所以我一直在 Chrome 开发工具控制台 (DCT
我知道在像 c 这样的语言中,我需要在分配内存后释放它。 (我来自 Java),对此我有几个问题: 当我在做的时候: int array[30]; (即创建一个大小为 30 个整数的数组)与
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: How to release pointer from boost::shared_ptr? Detach
我有一个可以从多个后台线程访问的类,可能同时访问。我无法复制该类,因为重新创建它的内容(处理或内存方面)可能很昂贵。 也有可能在后台处理仍在继续并访问该属性时替换了此类的属性。 目前我有定期的保留/释
这个问题是对: 的扩展链接-1:Creating an image out of the ios surface and saving it Link-2:Taking Screenshots fro
我有一个实例变量 NSMutableArray* searchResults。 首先,我初始化它: self.searchResults = [[NSMutableArray alloc] init]
如果我在堆上声明一些东西,比如 char *a=new char[1000] 并且主程序停止,如果没有 delete[]<,那么分配的内存会发生什么 调用?它保留在堆上还是自动释放? 最佳答案 就C+
在开发相机应用时,我遇到了一个异常,该异常仅在我切换到其他应用时发生(onPause() 用于我的应用)。 01-15 17:22:15.017: E/AndroidRuntime(14336): F
使用 JDK 1.8 编译时出现 maven 编译器错误 无法执行目标 org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (de
将 BufferedImage 保存到磁盘(以释放内存)的最快方法是什么? 我的 Java 应用程序处理大量图像(每约 300 毫秒将图像加载到内存中)。大多数这些图像都会立即被丢弃 (gc),但每隔
使用 JDK 1.8 编译时出现 maven 编译器错误 未能在项目 DUMMY 上执行目标 org.apache.maven.plugins:maven-compiler-plugin:3.8.1:
我是一名优秀的程序员,十分优秀!