简体   繁体   中英

Xcode: Unable to stop AVAudioPlayer music playing from sub class

STILL NO SOLUTION - REDUCED TEST CASE PROJECT HERE:

http://www.friendlycode.co.uk/assets/Bugfix.zip

I'm new to Xcode/Objective C and have done a lot of research but cannot find an answer. There are loads of similar questions here but none of them have helped me solve this.

Files:

app.h
app.m
Settings.h
Settings.m

I have some background music playing which starts when the app is launched via ViewDidLoad in the ViewController.m file.

I am trying to stop this from the Settings.m file if the Music switch is touched and set to off.

Please see code below (have removed unnecessary outlets/methods etc)

The NSLog outputs 'attempting to stop audio' but audio is not stopped. I think I have referenced the ViewController class correctly so unsure why it won't stop?

app.h

#import <UIKit/UIKit.h>
#import <Social/Social.h>
#import "AVFoundation/AVAudioPlayer.h"

@interface ViewController : GAITrackedViewController <AVAudioPlayerDelegate, UIActionSheetDelegate>
{
    // removed
}

@property (nonatomic, retain) AVAudioPlayer *BackgroundMusicPlayer;

@end

app.m

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Play Background music
    [self PlayBackgroundMusic];
}

-(void)PlayBackgroundMusic
{
    NSString* resourcePath = [[NSBundle mainBundle]
                            pathForResource:@"music-file"
                            ofType:@"aiff"];

    NSLog(@"Path to play: %@", resourcePath);
    NSError* err;

    //Initialize our player pointing to the path to our resource
    _BackgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:
              [NSURL fileURLWithPath:resourcePath] error:&err];

    if( err ){
        //bail!
        NSLog(@"Failed with reason: %@", [err localizedDescription]);
    }
    else{
        //set our delegate and begin playback
        _BackgroundMusicPlayer.delegate = self;
        [_BackgroundMusicPlayer play];
        _BackgroundMusicPlayer.numberOfLoops = -1;
        _BackgroundMusicPlayer.currentTime = 0;
        _BackgroundMusicPlayer.volume = 0.5;
    }
}

Settings.h

#import <UIKit/UIKit.h>
#import "app.h"

@interface Settings : GAITrackedViewController <AVAudioPlayerDelegate, UIActionSheetDelegate>
{
    IBOutlet UIButton *BackButton;
    IBOutlet UISwitch *MusicSwitch;
    IBOutlet UISwitch *SoundFXSwitch;


    // Get instance of ViewController object
    ViewController *home;
}

-(IBAction)BackButton:(id)sender;
-(IBAction)ToggleMusic:(id)sender;
-(IBAction)ToggleSoundFX:(id)sender;


@end

Settings.m

#import "Settings.h"

@interface Settings ()

@end

@implementation Settings

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

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

}

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

-(IBAction)ToggleMusic:(id)sender {

    // Get instance of ViewController object

    //home = [[ViewController alloc] init];

    if (MusicSwitch.on)
    {
        [home.BackgroundMusicPlayer play];
    }
    else {
       [home.BackgroundMusicPlayer stop];
        NSLog(@"Attempting to stop audio");

    }
}

-(IBAction)ToggleSoundFX:(id)sender {

    if (SoundFXSwitch.on)
    {
    }
    else{

    }
}

-(IBAction)BackButton:(id)sender
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

I think the problem is with the ViewController *home.

Your AvAudioPlayer object is in the app.h in the interface ViewController.

But in your code , you are not initialising the ViewController object "home" in settings.m. So effectively , you are trying to access and stop a player that is not created.

To access the AVAudioPlayer object add the following code in your viewDidload of settings.h.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    //initialise the audioPlayer object.
    home=[[ViewController alloc] init];
}

In your Settings.h , declare the ViewController property as assign

@interface Settings : GAITrackedViewController <UIActionSheetDelegate>
{
    @property (nonatomic, assign) ViewController *home;
}


-(IBAction)ToggleMusic:(id)sender {

    if (MusicSwitch.on)
    {
        [self.home.BackgroundMusicPlayer play];
    }
    else {

       [self.home.BackgroundMusicPlayer stop];
    }
}

From your app.m , assign the home property as self _BackgroundMusicPlayer.home = self;

-(void)PlayBackgroundMusic
{
    NSString* resourcePath = [[NSBundle mainBundle]
                            pathForResource:@"music-file"
                            ofType:@"aiff"];

    NSLog(@"Path to play: %@", resourcePath);
    NSError* err;

    //Initialize our player pointing to the path to our resource
    _BackgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:
              [NSURL fileURLWithPath:resourcePath] error:&err];

    if( err ){
        //bail!
        NSLog(@"Failed with reason: %@", [err localizedDescription]);
    }
    else{
        //set our delegate and begin playback
        _BackgroundMusicPlayer.delegate = self;
        settingsViewObj.home = self; //recommended after the 'Settings' view allocation code.
        [_BackgroundMusicPlayer play];
        _BackgroundMusicPlayer.numberOfLoops = -1;
        _BackgroundMusicPlayer.currentTime = 0;
        _BackgroundMusicPlayer.volume = 0.5;
    }
}

Notes:

  • Read more about object communication

  • Read more about Objective C coding standards

  • Read more about class hierarchy

If I am understanding your code correctly, it seems you are creating a instance of your initial view controller and trying to stop the music player property of that instance. If that is the case, the music player you are trying to stop is already stopped, because it is aa separate instance of AVAudioPlayer that was created when you created an instance of your ViewController. In order to stop the music player from the first view controller, you could try this:

  1. In the Settings.h file, add an AVAudioPlayer property just like in app.h

     @property (strong, nonatomic) AVAudioPlayer *backgroundMusic; 
  2. Then when segueing to the settings view controller, pass the audio player to the new controller using prepareForSegue:

     - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if([segue.identifier isEqualToString:@"YourSegueName"]) { if([segue.destinationViewController isKindOfClass:[YourSettingsClass class]]) { YourSettingsClass *destination = segue.destinationViewController; destination.backgroundMusic = self.BackgroundMusicPlayer; } } } 
  3. You should now be able to simply call [self.backgroundMusic stop] and stop your tunes.

Ensure that you #import your Settings controller class in your app class to access it in the prepareForSegue method.

You can't access the instance of an object of another class created by it, by importing it.Here You have to access the same object instance , in order to stop the AVAudioPlayer.

So you have to place the object somewhere unique, like AppDelegate.

Try declaring the AVAudioPlayer in the appdelegate.h.

In Appdeleagte.h

@property (nonatomic, strong) AVAudioPlayer *BackgroundMusicPlayer;

and in your app.h you can access the player as follows.

AppDelegate *appDelegate;

//in your viewDidLoad
    appDelegate=[[UIApplication sharedApplication]delegate]; 

//in your PlayBackGroundMusic
       appdelegate.avAudioPlayer=[[AVAudioPlayer alloc] initWithContentsOfURL:
                  [NSURL fileURLWithPath:resourcePath] error:&err];
       [appDelegate.avAudioplayer play];

in your settings.h

AppDeleagte *appDelegate;

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    //initialise the audioPlayer object.
    appDelegate=[[UIApplication sharedApplication]delegate]; 


}

you can stop the player by

[appDelegate.avAudioPlayer stop];

You can download the fixed project here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM