我继承了一些需要整理的代码。该应用程序具有少数核心声音,目前,有许多AVAudioPlayer
实例附加到各种ViewController
上,它们都播放相同的少数声音。
作为重构练习的一部分,我决定实现一个名为SoundController
的单例类。该类将为每个需要播放的声音包含一个AVAudioPlayer
,而不是每个ViewController
实例化自己的声音,它们可以轻松地仅使用一种:
[[SoundController controller].majorFunctionSound playAtTime:0];
另一重要的事情是确保在使用所有声音之前调用prepareToPlay:,以最大程度地减少延迟。由于只有少数几种声音,并且它们很可能在任何用户会话期间都将使用,因此在首次实例化SoundController时预装所有声音(在后台线程上)是有意义的。在初始化方法中,我有类似以下内容:
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];
});
majorAudioSound是
(readonly, strong)
。 @synthesize majorAudioSound = _majorAudioSound
。我担心的是,这在并行性方面的工作效果如何(或很好),以及我可以做些什么来改进代码。具体来说,如果我这样做:
[[SoundController controller].majorFunctionSound playAtTime:0];
显然,根据后台初始化块是否已完成,majorFunctionSound可能无法正确启动。如果属性返回
nil
并且声音根本无法播放,会发生的情况更糟吗?还有什么其他问题?有没有办法始终确保正确设置AVAudioPlayer?
最佳答案
首先,我想让您再考虑一下您的类是否必须为单例,因为您只打算拥有一个实例。当然,这是一种方法,但是我认为您的初始化问题继承自您决定使用单例类的事实。
假设您有一个名为SoundManager的类,并且已将其设置为Singleton类。
当您在应用程序中的任何位置请求SoundManager的实例时,您将要假定返回的实例已准备就绪,可以立即使用。如果您的SoundManager内部有一个异步的init方法,那么您确实会遇到设计问题,因为您不必知道何时第一次请求Singleton时是否已对其进行初始化。
由于SoundManager需要初始化,因此我会让我的应用在某种基类中拥有一个SoundManager实例,该实例负责应用程序的流程,而不是使其成为Singleton。您可以只让您的AppDelegate实例化一个唯一的SoundManager,或者您可以拥有一个名为ApplicationController的类,或者在初始化时加载该应用所需的所有内容的类。然后,您可以通过此控制器类通过传递引用或让您的ApplicationController为单例来访问SoundManager实例。当然,如果SoundManager是singleton,这也可以工作,只要您确保在启动时将其初始化即可,但是我更希望拥有尽可能少的singleton类。
现在是关于您的声音是否加载的问题。
我建议您先加载所有声音,然后再让用户开始使用该应用程序。同时,您可以向用户显示一些内容,例如加载屏幕,进度条,并根据需要播放声音/音乐。这是一个结构示例:
创建一个名为SoundManager的类,其属性“ loaded”从一开始就为假
创建一个名为ApplicationController的类来实例化SoundManager,以及其他可能有用的类,例如TextureManager或LocationManager等。
应用程序启动时,实例化ApplicationController,后者又实例化SoundManager。
显示载入画面
让SoundManager先加载“加载声音”,然后在加载后开始播放
声音加载完成后,将“ loaded”属性设置为true
当ApplicationController加载完所有内容后,让用户通过淡出加载屏幕开始使用该应用程序。
如果您需要用户甚至在加载声音之前就开始使用该应用程序,那么您仍然可以通过使用名为“ loaded”的属性来使用相同的方法。记住要保持该属性的处理同步。
关于objective-c - iOS:在后台加载声音时出现多线程问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11931174/