Reputation: 29
I have a couple of views, one being the SettingsMenu the other being Game .
I have initialised backgroundMusic from within Game. When there is a change in SettingsMenu, I'd like it to run backgroundMusicStop in settingsMenu, however backgroundMusicStop is part of my Game class.
Game.h
-(void)backgroundMusicStop;
Game.m
-(void)backgroundMusicStop {
[backgroundMusic stop];
backgroundMusic.currentTime = 0;
}
SettingsMenu.m
-(IBAction)musicOptionSwitch:(id)sender {
if (backgroundMusicPlay == YES) {
backgroundMusicPlay = NO;
[Game backgroundMusicStop];
}
}
I've looked into it and I don't understand how to fix it, I know I need to make the method accessible from all classes, but I am confused on how to do that, any help would be greatly appreciated.
Upvotes: 0
Views: 52
Reputation: 31016
I think the best architecture for what you're trying to do would be:
create one instance of a Settings object and have it keep track of the current state of each option you want the user to control
update those values from inside your SettingsMenu
have your Game listen for changes to the Settings values
The advantage in this is that your view controllers only communicate through changes to the data model (Settings) rather than having to know about each other. Your Settings object can either be a singleton or a normal object that you get from your app delegate.
First create the settings data model:
// Settings.h
#import <Foundation/Foundation.h>
@interface Settings : NSObject
// A singleton so that the example stays simple
+ (instancetype)sharedSettings;
// YES/NO. Add other properties as needed.
@property (nonatomic, assign) BOOL musicShouldPlay;
#define MUSIC_SHOULD_PLAY @"musicShouldPlay"
@end
// Settings.m
#import "Settings.h"
@implementation Settings
// Guarantee only one instance
+ (instancetype)sharedSettings {
static dispatch_once_t onceToken;
static Settings *result = nil;
dispatch_once(&onceToken, ^{
result = [[Settings alloc] init];
});
return result;
}
- (instancetype)init {
self = [super init];
if (self) {
_musicShouldPlay = NO;
}
return self;
}
@end
The controller that makes the changes:
// SettingsViewController.m
#import "SettingsViewController.h"
#import "Settings.h"
@interface SettingsViewController ()
@property (strong, nonatomic) IBOutlet UISwitch *musicSwitch;
@end
@implementation SettingsViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Make the display consistent with previous settings
[self.musicSwitch setOn:[[Settings sharedSettings] musicShouldPlay]];
}
// I'm presenting this using a modal segue from a "Change settings" button on the main controller,
// so it has a "Done" button
- (IBAction)done:(id)sender {
[ self dismissViewControllerAnimated:YES completion:nil];
}
// Switch value changes are connected to this in the storyboard
- (IBAction)changePlayState:(id)sender {
[[Settings sharedSettings] setMusicShouldPlay:[self.musicSwitch isOn]];
}
@end
The controller that reacts to changes:
// ViewController.m
#import "ViewController.h"
#import "Settings.h"
@implementation ViewController
// Since this is the primary controller, I'll have it listen for its lifetime.
- (void)viewDidLoad {
[super viewDidLoad];
[[Settings sharedSettings] addObserver:self
forKeyPath:MUSIC_SHOULD_PLAY
options:NSKeyValueObservingOptionNew
context:nil];
}
- (void)dealloc {
[[Settings sharedSettings] removeObserver:self forKeyPath:MUSIC_SHOULD_PLAY];
}
// Here's where the KVO notifications are delivered.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:MUSIC_SHOULD_PLAY]) {
NSNumber *newValue = [change valueForKey:NSKeyValueChangeNewKey];
if ([newValue integerValue] == 1) {
NSLog(@"Request to turn music on");
} else {
NSLog(@"Request to turn music off");
}
}
}
@end
Upvotes: 1
Reputation: 7440
The problem is in this line of code:
[Game backgroundMusicStop];
In your implementation, Game is a class name and you try to call an instance method on a class. There are 2 options to fix it:
To create a Game instance you would need something like:
Game myGame = [[Game alloc]init];
//depending on your implementation it could be different
Or if you choose for second option you will have to change
-(void)backgroundMusicStop;
to
+(void)backgroundMusicStop;
I would also suggest you to find some book/website to understand class and instance variables/methods better and more in-depth.
Upvotes: 2