7

这个问题可能太模糊而无法通过StackOverflow's标准,但我必须尝试发布它,因为我没有选择......:/

长话短说:我有一个应用程序会经历随机的缓慢期。它不会经常发生(可能每月一次),但是当它只完全重新启动它运行的 iDevice 时会有所帮助。症状是: 2-3 秒的响应时间和缓慢、断断续续的动画;整个应用程序基本上变得无法使用。

我已经通过所有可能的诊断工具运行了该应用程序,但都没有发现任何问题;没有内存泄漏或异常高的 CPU 使用率。但是,这并不奇怪,因为该应用程序非常简单,是一款纸牌游戏的追踪器应用程序。

所有这一切让我相信,AVAudioPlayer当用户点击 a 时,我用来播放声音的button可能是问题的原因(它是整个应用程序中唯一的、相对复杂度较高的元素)。但是,我不确定,这是我需要帮助的地方。我在这里包含了一个示例代码,也许有iOS音频播放经验的人可以查看它,看看是否有我忽略的错误。

我们开始吧:首先,我初始化一个“静音播放器”,它每秒都在播放静音曲目以保持AVAudioPlayer活力。这是必要的,因为AVAudioPlayer在较长时间的不活动后被调用时会经历相对较长的响应时间。

NSString *silenceFilePath = [[NSBundle mainBundle] pathForResource: @"silence" ofType: @"wav"];
NSURL *silenceFileURL = [[NSURL alloc] initFileURLWithPath: silenceFilePath];
silencePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: silenceFileURL error: nil];
[silencePlayer setDelegate: self];
[silencePlayer prepareToPlay];

silenceTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f
                                                target:self
                                              selector:@selector(repeatSilence)
                                              userInfo:nil
                                               repeats:YES];

NSTimer 调用以下方法:

- (void) repeatSilence
{
    if (isAudioON == YES)
    {
        if (silencePlayer.playing)
        {
            [silencePlayer stop];
            silencePlayer.currentTime = 0;
            [silencePlayer play];
        }
        else
        {
            [silencePlayer play];
        }
    }
}

其余的相当简单。我启动另一个 AVAudioPlayer 来播放特定的按钮声音(其中有两个):

NSString *buttonSoundFilePath = [[NSBundle mainBundle] pathForResource: @"button_pushed" ofType: @"wav"];
NSURL *buttonFileURL = [[NSURL alloc] initFileURLWithPath: buttonSoundFilePath];
buttonPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: buttonFileURL error: nil];
[buttonPlayer setDelegate: self];
[buttonPlayer prepareToPlay];

当按下按钮时,我会播放声音(与静音播放器的播放方式相同):

if (isAudioON == YES)
{
    if (buttonPlayer.playing)
    {
        [buttonPlayer stop];
         buttonPlayer.currentTime = 0;
        [buttonPlayer play];
    }
    else
    {
        [buttonPlayer play];
    }
}

真的是它的全部。然而,我担心,尽管这种方法很简单,但不知何故,这种连续的音频播放会造成 iOS 发疯的罕见实例。但这一切都只是一个理论,这就是为什么我需要有更多经验的人来看看我的代码并分享他的意见。

谢谢!

更新: 我发现另外几行代码也可能与问题相关。有了它们,我将 AVAudioPlayer 设置为与后台播放的音乐同时工作(例如,来自另一个应用程序):

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[AVAudioSession sharedInstance] setDelegate:self];
4

2 回答 2

4

从我从您的问题中收集到的信息来看,您想要播放的唯一声音似乎是相对简单且简短的音效。如果情况确实如此,我不会使用 AVAudioPlayer,因为它是一个资源繁重的库,用于以固定音量播放音效等简单的事情。我会直接使用音频服务。这是我从其他地方提取的声音效果类的示例(不记得在哪里了)。

音效.h

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>

@interface SoundEffect : NSObject
{
    SystemSoundID soundID;
}

- (id)initWithSoundNamed:(NSString *)filename;
- (void)play;

@end

音效.m

#import "SoundEffect.h"

@implementation SoundEffect

- (id)initWithSoundNamed:(NSString *)filename
{
    if ((self = [super init]))
    {
        NSURL *fileURL = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
        if (fileURL != nil)
        {
            SystemSoundID theSoundID;
            OSStatus error = AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &theSoundID);
            if (error == kAudioServicesNoError)
                soundID = theSoundID;
        }
    }
    return self;
}

- (void)dealloc
{
    AudioServicesDisposeSystemSoundID(soundID);
}

- (void)play
{
    AudioServicesPlaySystemSound(soundID);
}

@end

一旦你有了这个类,你可以使用以下代码轻松播放任何声音效果:

SoundEffect *mySoundEffect = [[SoundEffect alloc] initWithSoundNamed:@"mySound.wav"];
[shareSoundEffect play];

为了优化,我会在某处加载所有音效并静态存储它们,以便预加载实际的声音文件,然后在需要时调用它们的“播放”。与使用 AVAudioPlayer 相比,这样做是一种资源消耗更少的音效播放方式。谁知道,也许它会解决你的问题。

预加载声音文件:

我的意思比听起来简单。我的意思是,在程序首次加载时初始化每个 Sound Effect 对象后,您将为它们创建一个静态引用。有几种方法可以做到这一点。我通常使用 +load 方法。它看起来像这样:

在 SoundEffect 类的实现中添加一个静态变量

static SoundEffect *mySoundEffect;

接下来,在 Sound Effect 类的 +load 方法中初始化该变量。

+(void)load
{
    mySoundEffect = [[SoundEffect alloc] initWithSoundNamed:@"mySound.wav"];
}

现在只需为音效类创建一个静态方法,如下所示:

+(void)playMySound
{
    [mySoundEffect play];
}

之后,您可以随时通过调用来播放该声音:

[SoundEffect playMySound];

关于音量控制的说明:

我在我的几个 IOS 应用程序中使用此代码,我可以确认以下内容:

  1. 设备侧面的标准音量控件将正常工作,但前提是用户的设置指定可以使用按钮更改铃声和警报。
  2. 无法在代码中控制声音的音量。
于 2013-05-09T18:16:38.810 回答
1

我从上面的代码中观察到,我建议进行两项更改。

1)您使用了两个 AVAudioPlayer 实例,一个用于每秒连续播放无声的声音。AVAudioPlayer 的第二个实例用于在单击按钮时播放声音。同时运行两个 AVAudioPlayer 实例,因为在设备内存不足且需要同时播放静音和按钮声音的某个时间点,设备会运行缓慢。最好使用一个 AVAudioPlayer 实例来播放两种声音。

2) 继续播放静音,直到用户点击按钮。当用户单击按钮时,暂停计时器并停止当前声音并使用相同的 AVAudioPlayer 实例播放按钮声音。这样,当需要播放按钮声音时,大多数不推荐的计时器将停止一段时间,当按钮声音播放完毕时,恢复计时器以播放与 AVAudioPlayer 实例相同的静音声音。这将从内存和处理中带走大量负载。

于 2013-05-09T05:21:41.770 回答