Ios childViewController不';播放声音后不要释放

Ios childViewController不';播放声音后不要释放,ios,audio,singleton,avaudioplayer,Ios,Audio,Singleton,Avaudioplayer,我有一个pageViewController(UIPageViewController),它有一个子视图控制器(名为soundPlayer)。 声音播放器具有静态AVAudioPLayer*播放器 当在页面之间导航时,我们必须在播放器上(单例模式)。 所以,如果我在页面之间导航而不播放声音,最后从这些视图返回,控制器(导航控制器)soundPlayer将被释放。 但当我播放声音并在页面之间导航时,每翻页一个新的soundPlayer不会发布,而是会创建一个新的soundPlayer 在每次翻页播

我有一个pageViewController(UIPageViewController),它有一个子视图控制器(名为soundPlayer)。 声音播放器具有静态AVAudioPLayer*播放器 当在页面之间导航时,我们必须在播放器上(单例模式)。 所以,如果我在页面之间导航而不播放声音,最后从这些视图返回,控制器(导航控制器)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
#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
我上传了一个示例应用程序


简短回答:不要使用静态变量。你不了解它们是如何工作的,并且错误地使用它们。
您应该删除声音播放器上的“静态”限定符。

我建议您创建Singleton来管理AVAudioPlayer,如下所示

 #import "AudioManager.h"

 [[[AudioManager sharedManager] soundPlayer] play];
接口

// 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"
在其他视图控制器中,您可以参考singleton对象上的AVAudioPlayer属性,其中仅创建单个AudioManager对象,如下所示

 #import "AudioManager.h"

 [[[AudioManager sharedManager] soundPlayer] play];

我知道这就是原因。但我只需要一个AVAudioPlayer可以通过网页。所以我让它静止。你知道实现这一目标的其他方法吗?