Hello StackOverflow大师。这是我在这里的第一个问题所以我很高兴能够直接进入。
我试图更好地了解iOS阵列,并且我已经碰到了一堵砖墙。我正在制作一个使用FMOD的声音应用。我有一切工作完美,但我有9个按钮,所有都执行几乎完全相同的事情,除了每个按下播放不同的.wav文件然后发布停止声音。我想将它放入一个数组中,简化并缩短我的代码,这就是我迷失的地方。我删除了代码以显示我目前正在进行的操作。有什么想法吗?
·H
@interface {
FMOD::Sound *sound1;
FMOD::Sound *sound2;
FMOD::Sound *sound3;
FMOD::Sound *sound4;
FMOD::Sound *sound5;
FMOD::Sound *sound6;
FMOD::Sound *sound7;
FMOD::Sound *sound8;
FMOD::Sound *sound9;
}
- (IBAction)playSound1:(id)sender;
- (IBAction)stopSound1:(id)sender;
- (IBAction)playSound2:(id)sender;
- (IBAction)stopSound2:(id)sender;
- (IBAction)playSound3:(id)sender;
- (IBAction)stopSound3:(id)sender;
- (IBAction)playSound4:(id)sender;
- (IBAction)stopSound4:(id)sender;
- (IBAction)playSound5:(id)sender;
- (IBAction)stopSound5:(id)sender;
- (IBAction)playSound6:(id)sender;
- (IBAction)stopSound6:(id)sender;
- (IBAction)playSound7:(id)sender;
- (IBAction)stopSound7:(id)sender;
- (IBAction)playSound8:(id)sender;
- (IBAction)stopSound8:(id)sender;
- (IBAction)playSound9:(id)sender;
- (IBAction)stopSound9:(id)sender;
米。
- (void)viewWillAppear:(BOOL)animated {
[[NSString stringWithFormat:@"%@/sound1.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound1);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound2.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound2);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound3.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound3);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound4.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE, NULL, &sound4);
ERRCHECK(result);
result = sound4->setMode(FMOD_LOOP_NORMAL);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound5.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound5);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound6.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound6);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound7.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound7);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound8.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound8);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound9.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound9);
ERRCHECK(result);
}
- (IBAction)playSound1:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound1, false, &wob01);
ERRCHECK(result);
}
- (IBAction)stopSound1:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob01->stop();
ERRCHECK(result);
}
- (IBAction)playSound2:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound2, false, &wob02);
ERRCHECK(result);
}
- (IBAction)stopSound2:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob02->stop();
ERRCHECK(result);
}
- (IBAction)playSound3:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound3, false, &wob03);
ERRCHECK(result);
}
- (IBAction)stopSound3:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob03->stop();
ERRCHECK(result);
}
- (IBAction)playSound4:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound4, false, &wob04);
ERRCHECK(result);
}
- (IBAction)stopSound4:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob04->stop();
ERRCHECK(result);
}
- (IBAction)playSound5:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound5, false, &wob05);
ERRCHECK(result);
}
- (IBAction)stopSound5:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob05->stop();
ERRCHECK(result);
}
- (IBAction)playSound6:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound6, false, &wob06);
ERRCHECK(result);
}
- (IBAction)stopSound6:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob06->stop();
ERRCHECK(result);
}
- (IBAction)playSound7:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound7, false, &wob07);
ERRCHECK(result);
}
- (IBAction)stopSound7:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob07->stop();
ERRCHECK(result);
}
- (IBAction)playSound8:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound8, false, &wob08);
ERRCHECK(result);
}
- (IBAction)stopSound8:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob08->stop();
ERRCHECK(result);
}
- (IBAction)playSound9:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound9, false, &wob09);
ERRCHECK(result);
}
- (IBAction)stopSound9:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob09->stop();
ERRCHECK(result);
}
如您所见,所有代码都重复了。这是我能够让它工作的唯一方法,但我知道这些可以放入一个数组中,我无法弄明白。可能是NSMutableArray并列出“sound1”,“sound2”等等。然后在界面构建器中为每个按钮分配一个标签?理想情况下,我想为stopSound提供一个函数,一个用于playSound等,它使用标签来播放或停止正确的声音文件。当使用FMOD的system-> createSound()时,最后一个参数是一个变量来存储新创建的声音。有没有办法将它存储在数组或字典中呢?如果是这样,我无法理解。
任何建议都不仅仅是值得赞赏的。我很想不再对这个简单的问题大打折扣。
谢谢!
答案 0 :(得分:8)
我会将声音包装到NSObject
的子类中,并使其成为一个自包含的单元。声音会有play
,stop
,pause
和isPlaying
等访问器等操作。
然后为了使它更通用,我会搜索匹配模式"*.wav"
的所有文件,然后对于每个匹配的文件名,用该文件名初始化Sound
对象,并将其添加到阵列。
这就是我想象的Sound对象的样子:
@interface Sound : NSObject
@property FMOD::Sound *sound;
- (id)initWithSoundFilePath:(NSString *)path;
- (void)play;
- (void)stop;
@end
@implementation Sound
- (void)dealloc {
// free the memory occupied by the sound pointer here
}
- (id)initWithSoundFilePath:(NSString *)path {
self = [super init];
if (self) {
result = system->createSound(path, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound);
ERRCHECK(result);
}
return self;
}
- (void)play {
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound, false, /* What is this wob? */);
ERRCHECK(result);
}
- (void)stop {
FMOD_RESULT result = FMOD_OK;
result = /* What is this wob */->stop();
ERRCHECK(result);
}
@end
所以你有它。声音很好地封装了。我发现这个answer有助于查找符合某些条件的特定目录中的所有文件的列表。您可以在视图控制器中使用它来自动生成所有相关的Sound对象并将其添加到数组中。
- (NSArray *)getPathsOfSoundFiles {
NSString *rootPath = [[NSBundle mainBundle] resourcePath];
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *files = [fm contentsOfDirectoryAtPath:rootPath error:nil];
NSPredicate *soundFileFilter = [NSPredicate predicateWithFormat:@"self ENDSWITH '.wav'"];
NSArray *soundFilePaths = [files filteredArrayUsingPredicate:soundFileFilter];
return soundFilePaths;
}
好了,现在您可以检索所有.wav文件的路径,下一步是在viewWillAppear
或其他最有意义的方法中初始化它们。
- (void)viewWillAppear:(BOOL)animated {
NSArray *paths = [self getPathsOfSoundFiles];
NSMutableArray *sounds = [NSMutableArray array];
for (NSString *path in paths) {
Sound *sound = [[Sound alloc] initWithSoundFilePath:path];
[sounds addObject:sound];
}
self.sounds = sounds;
}
通过声音阵列设置,播放和停止给定声音变得相当容易。使用可以创建一个方法,将索引引入数组,或者可能是Sound
对象本身并完成工作。
- (void)playSoundAtIndex:(NSUInteger)soundIndex {
Sound *sound = [self.sounds objectAtIndex:soundIndex];
[sound play];
}
- (void)stopSoundAtIndex:(NSUInteger)soundIndex {
Sound *sound = [self.sounds objectAtIndex:soundIndex];
[sound stop];
}
答案 1 :(得分:1)
您可以大量概括您的代码:
[NSString stringWithFormat:@"%@/sound%i.wav", [[NSBundle mainBundle] resourcePath], index]
-playSound:
和一个-stopStound:
操作使用sender
的{{3}}(您可以在Interface Builder中设置或在您的按钮中创建按钮时自动化查看控制器的代码)以确定要播放的声音或要停止的声音。答案 2 :(得分:-3)
我强烈建议您继承UIButton并覆盖触摸方法,以便在发生这些操作时播放音频文件。当您对UIButton进行子类化时,您需要在头文件中设置一个属性,以便传入音频文件或音频文件所在的字符串,这样就可以很容易地使其动态化。
然后在主文件中,就像我说的那样只是覆盖那些触摸方法(touchesBegan,touchesEnded等)来播放我们在头文件中定义的自定义属性。
这就是我至少解决你的问题的方法,那么你只有一个UIButton子类可以做同样的事情,具体取决于你传入的音频文件。