0

我继承了一些需要整理的代码。该应用程序有一些核心声音,目前,有很多AVAudioPlayer实例附加到各种ViewController播放相同的几个声音。

作为重构练习的一部分,我决定实现一个名为SoundController. 这个类将为AVAudioPlayer需要播放的每个声音包含一个,而不是每个ViewController实例化自己的,他们可以轻松地只使用一个:

[[SoundController controller].majorFunctionSound playAtTime:0];

另一个重要的事情是确保在所有声音被使用之前都调用了 prepareToPlay: 以最小化任何延迟。由于只有少数声音并且它们都可能在任何用户会话期间使用,因此在 SoundController 首次实例化时预加载所有声音(在后台线程上)是有意义的。在 init 方法中,我有这样的东西:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, nil, ^(void)          
{
NSURL *soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/MAJOR FUNCTION.m4a", [[NSBundle mainBundle] resourcePath]]];
_majorAudioSound = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
[_majorAudioSound  prepareToPlay];
});

主要音频是(readonly, strong). @synthesize majorAudioSound = _majorAudioSound.

我担心的是这在并发方面的工作有多差(或好),以及我可以做些什么来改进代码。具体来说,如果我这样做:

[[SoundController controller].majorFunctionSound playAtTime:0];

显然,majorFunctionSound 有可能无法正确启动,具体取决于后台初始化块是否已完成。nil财产返回并且声音根本不播放会发生更糟糕的情况吗?

可能还有什么问题?有没有办法始终确保 AVAudioPlayer 已正确设置?

4

1 回答 1

1

首先,我想让你重新考虑一下你的类是否必须是单例,因为你打算只拥有它的一个实例。这当然是一种方法,但我认为您的初始化问题继承自您决定使用单例类的事实。

假设您有一个名为 SoundManager 的类,并且您已将其设为 Singleton 类。

当您在应用程序的任何位置请求 SoundManager 的实例时,您会希望假定返回的实例已准备好立即使用。如果您在 SoundManager 中有一个异步的 init 方法,那么您确实存在设计问题,因为您永远不必知道何时请求 Singleton 是否是第一次初始化。

由于 SoundManager 需要初始化,我会让我的应用程序在某种处理应用程序流的基类中拥有 SoundManager 的实例,而不是使其成为 Singleton。要么你可以让你的 AppDelegate 实例化唯一的 SoundManager,或者你可以有一个名为 ApplicationController 的类,或者你可以在应用程序初始化时加载应用程序所需的所有内容。然后,您可以通过此控制器类通过传递引用或让您的 ApplicationController 成为单例来访问 SoundManager 实例。当然,如果 SoundManager 是单例的,只要确保在启动时对其进行初始化,这也有效,但我更喜欢尽可能少的单例类。

现在回答您关于知道您的声音是否已加载的问题。

我建议您在让用户开始使用应用程序之前加载所有声音。同时,你可以向用户展示一些东西,比如加载屏幕、进度条,如果你愿意的话还可以播放声音/音乐。下面是一个结构示例:

  • 创建一个名为 SoundManager 的类,其属性“已加载”从一开始就为假
  • 创建一个名为 ApplicationController 的类来实例化 SoundManager,以及您可能拥有的其他有用的类,如 TextureManager 或 LocationManager 等。
  • 当应用程序启动时,实例化 ApplicationController,然后实例化 SoundManager。
  • 显示加载屏幕
  • 让 SoundManager 先加载“加载声音”,加载后开始播放
  • 声音加载完成后,将“loaded”属性设置为true
  • 当 ApplicationController 加载完所有内容后,让用户通过淡出加载屏幕来开始使用应用程序。

如果您需要用户在加载声音之前就开始使用应用程序,那么您仍然可以通过拥有一个名为“已加载”的属性来使用相同的方法。请记住保持此属性的处理同步。

于 2012-08-13T09:38:31.637 回答