I try to extend the functionality of SimpleAudioEngine of cocos2d with the ability to play several sound effect one after another as some kind of chain. I tried to do this with an extension. However I now realized that I probably also need an iVar to remember the names of all sound files and one to remember which sound is currently playing.
However it seems that I cannot add iVars in a category. Instead I tried to use an extension, but it seems that they need to be in the original .m file of the class so that also would not work. Is there yet another way, that allows me to do this?
The header with the category
#import <Foundation/Foundation.h>
@interface SimpleAudioEngine(SoundChainHelper)<CDLongAudioSourceDelegate>
-(void)playSoundChainWithFileNames:(NSString*) filename, ...;
@end
And the .m-file with the extension:
#import "SoundChainHelper.h"
@interface SimpleAudioEngine() {
NSMutableArray* soundsInChain;
int currentSound;
}
@end
@implementation SimpleAudioEngine(SoundChainHelper)
// read in all filenames and start off playing process
-(void)playSoundChainWithFileNames:(NSString*) filename, ... {
soundsInChain = [[NSMutableArray alloc] initWithCapacity:5];
va_list params;
va_start(params,filename);
while (filename) {
[soundsInChain addObject:filename];
filename = va_arg(params, NSString*);
}
va_end(params);
currentSound = 0;
[self cdAudioSourceDidFinishPlaying:nil];
}
// play first file, this will also always automatically be called as soon as the previous sound has finished playing
-(void)cdAudioSourceDidFinishPlaying:(CDLongAudioSource *)audioSource {
if ([soundsInChain count] > currentSound) {
CDLongAudioSource* mySound = [[CDAudioManager sharedManager] audioSourceForChannel:kASC_Right];
[mySound load:[soundsInChain objectAtIndex:0]];
mySound.delegate = self;
[mySound play];
currentSound++;
}
}
@end
Alternatively I tried to define the iVars as properties, which will compile. However I can neither synthesize them nor do I have any other possibility to bind them to any method.
I try to implement the functionality as a category of SimpleAudioEngine so that I only need to remember one class that deals with all my sound issues. and so that I can create a chain as simple as this:
[[SimpleAudioEngine sharedEngine] playSoundChainWithFileNames:@"6a_loose1D.mp3", @"6a_loose2D.mp3", @"6a_loose3D.mp3", @"6a_loose4D.mp3", @"6b_won1D.mp3", nil];
If there is another way that yields the same/ a similar result I would also be very thankful.
For a private/protected variable, use iVar; for a public variable, use property. If you want to use the benifit of property attributes for a private variable, like retain, nonatomic etc., declare the property in the implementation file as a private property.
A category allows you to add methods to an existing class—even to one for which you do not have the source. Categories are a powerful feature that allows you to extend the functionality of existing classes without subclassing. Check the apple doc for the Category in Objective-C.
Categories provide the ability to add functionality to an object without subclassing or changing the actual object. A handy tool, they are often used to add methods to existing classes, such as NSString or your own custom objects.
Category and extension both are basically made to handle large code base, but category is a way to extend class API in multiple source files while extension is a way to add required methods outside the main interface file.
You are correct that you can't add instance variables (or synthesized @properties) to a category. You can workaround this limitation using the Objective-C runtime's support for Associative References
Something like this:
In your .h:
@interface SimpleAudioEngine (SoundChainHelper)
@property (nonatomic, retain) NSMutableArray *soundsInChain;
@end
In your .m:
#import <objc/runtime.h>
static char soundsInChainKey;
@implementation SimpleAudioEngine (SoundChainHelper)
- (NSMutableArray *)soundsInChain
{
return objc_getAssociatedObject(self, &soundsInChainKey);
}
- (void)setSoundsInChain:(NSMutableArray *)array
{
objc_setAssociatedObject(self, &soundsInChainKey, array, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
(The standard disclaimer applies. I typed this in the browser, and didn't test it, but I have used this technique before.)
The documentation I linked to has a lot more information about how associative references work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With