Mark D
Mark D

Reputation: 257

How can I keep background music playing when switching ViewControllers?

I currently have a SettingsViewController which handles starting/stopping music and adjusting the musics volume.

Is it possible to make the music stay on after unwinding the SettingsViewController? And after turning on the music and switching ViewControllers, can I re-open the SettingsViewController and turn off the music as well? Please let me know the limitations.

Here is the code for my SettingsViewController.h

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface SettingsViewController : UIViewController <AVAudioPlayerDelegate>
{
    AVAudioPlayer *audioPlayer;
    IBOutlet UISwitch *Switch;
    IBOutlet UISlider *Slider;

}
-(IBAction)Switch:(UISwitch *)sender;
-(IBAction)Slider:(UISlider *)sender;
@end

And here is the code for my SettingsViewController.m

#import "SettingsViewController.h"

@interface SettingsViewController ()

@end

@implementation SettingsViewController

-(IBAction)Switch:(UISwitch *)sender{
    NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];

    if(sender.tag == 0){
        if(sender.on){
            [standardDefaults setObject:@"On" forKey:@"keyName"];
            //choosing and setting the music file
            NSString *music = [[NSBundle mainBundle]pathForResource:@"bgmusic1" ofType:@"mp3"];
            audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
            audioPlayer.delegate = self;
            audioPlayer.numberOfLoops= -1; //sets the music to loop infinitely
            [audioPlayer play]; //plays the music


        } else if (sender.on == 0){
            [standardDefaults setObject:@"Off" forKey:@"keyName"];
            [audioPlayer stop]; //stops the music
        }
    }
    [standardDefaults synchronize];

}

-(IBAction)Slider:(UISlider *)sender{
    audioPlayer.volume = sender.value / 100.0; //will adjust the volume of the music according the slider value
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    }

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

Let me know what needs to be modified!

Upvotes: 1

Views: 179

Answers (2)

Luan Tran
Luan Tran

Reputation: 1142

Because your audioPlayer will be release when its parent SettingsViewController released.

So you should add it to global and you can make it with Singleton Pattern.

Create BackgroundPlayer.h

@interface BackgroundPlayer: NSObject {
   AVAudioPlayer *audioPlayer;
}

+ (id)sharedManager;

@end

and BackgroundPlayer.m

@implementation BackgroundPlayer

static BackgroundPlayer* sharedInstance = nil;

+ (BackgroundPlayer*) sharedInstance {
    if (sharedInstance == nil) {
        sharedInstance = [[super allocWithZone:NULL] init];
    }

    return sharedInstance;
}

- (id)init
{
    self = [super init];

    return self;
}

-(void)playAudio:(NSString *) audioPath
{
    audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:audioPath] error:NULL];
    audioPlayer.delegate = self;
    audioPlayer.numberOfLoops= -1; //sets the music to loop infinitely
    [audioPlayer play]; //plays the music
}

-(void)setVolum:(float) volum {
    if (audioPlayer) {
        audioPlayer.volume = sender.value / 100.0;
    }
}

Then you just call

NSString *music = [[NSBundle mainBundle]pathForResource:@"bgmusic1" ofType:@"mp3"];
[[BackgroundPlayersharedInstance] playAudio:music];

Upvotes: 0

Pat_Morita
Pat_Morita

Reputation: 3545

Do that in your AppDelegate.

To access it from anywhere, import it's .h file in your ViewControllers .m file and access it with

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];

Make the audioplayer to a property in your AppDelegate.h to allow public access (for e.g. your other viewControllers)

@interface AppDelegate: NSAppDelegate
 {
    IBOutlet UISwitch *Switch;
    IBOutlet UISlider *Slider; 
}

@property AVAudioPlayer *audioPlayer; // <------
-(IBAction)Switch:(UISwitch *)sender;
-(IBAction)Slider:(UISlider *)sender;
@end

Then adjust each call of your audioplayer in the m file to adopt the change in your h file.

//Instead of [audioplayer doSomething] write...
[self.audioplayer doSomething];

// in modern objective-c you can use also
[_audioplayer doSomething];

To call your audioplayer from other ViewControllers then implement the first mentioned code and call your player like so

[appDelegate.audioplayer doSomething]

Upvotes: 1

Related Questions