This might be a basic question, but I'm new to Cocoa and Objective-C and OOP in general, and I haven't been able to find an answer to this anywhere.
In an app I'm writing, I want to play a sound file whenever the user presses a particular button. I'm using NSSound for that and have no problem implementing it. The problem is, I only know how to do it by creating a new NSSound object each time the button is pressed:
- (IBAction)playSound:(id)sender {
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:kSoundFilePath byReference:YES];
[sound play];
}
This is an issue for me because if the user clicks the button repeatedly before the file finishes playing, it will create new instances of NSSound and they will all play on top of each other, which I don't want. Is there a way that I can create the NSSound object outside of that method, and have the IBAction method for the button check to see if the NSSound is playing before telling it to play again?
Yessir. This can be done several ways. One easy way is to use a private property:
/* these are in the SAME FILE */
@interface MyClass ()
@property (nonatomic, retain) NSSound *sound;
@end
@implementation MyClass
- (IBAction)playSound:(id)sender {
self.sound = [[NSSound alloc] initWithContentsOfFile:kSoundFilePath byReference:YES];
[self.sound play];
}
@end
You can also do it this way. EDIT: As Avt stated in the comments, there are some issues when using a global variable in his fashion. If you ever will be creating multiple instances of this class, you might be better off using a singleton design pattern. To explain, here's an article by the venerable Mattt Thompson.
@implementation MyClass
NSSound *sound;
...
- (IBAction)playSound:(id)sender {
sound = [[NSSound alloc] initWithContentsOfFile:kSoundFilePath byReference:YES];
[sound play];
}
@end
I personally use the first way because it makes it more clear from a programming standpoint that your class owns the created object. Though the second way is legal, it is less clear where the object belongs... it could be a local variable in the method's scope, or something else. I would highly recommend the first way, but in the interest of education you should know about all possible ways.