0

我继承了一些需要稍微整理的代码。该应用程序有一些核心声音,目前,有很多AVAudioPlayer实例附加到各种ViewController的播放相同的几个声音。iOS:在后台加载声音时出现多线程问题

作为重构练习的一部分,我决定实现一个名为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的设置正确?

回答

1

首先,我想让你再考虑一下,你的班级是否必须是单身人士,因为你打算只有一个单身人士。这当然是一种方法,但我认为你的初始化问题是继承于你决定使用单例类的事实。

可以说你有一个名为SoundManager的类,并且你已经将它变成了一个Singleton类。

当您在应用程序中的任何位置询问SoundManager的实例时,您将需要假定返回的实例已准备好立即使用。如果你的SoundManager中有一个init方法是异步的,那么你确实有设计问题,因为如果你是第一次请求Singleton,或者它没有被初始化,你永远都不需要知道什么时候。

由于SoundManager需要初始化,因此我会让我的应用程序在某种基类中处理SoundManager的一个实例,该基类负责处理应用程序流,而不是将其设置为Singleton。要么你可以让你的AppDelegate实例化唯一的SoundManager,或者你可以有一个名为ApplicationController的类,或者在初始化时加载你需要的所有东西。然后你可以通过传递一个引用或者让你的ApplicationController成为一个单例来通过这个控制器类访问SoundManager实例。当然,如果SoundManager是单身人士,这也可以工作,只要你确保在启动时初始化它,但我更喜欢尽可能少的单身人士。

现在你的问题关于知道你的声音是否加载。

我建议您在让用户开始使用应用程序之前加载所有声音。与此同时,您可以向用户展示某些内容,如加载屏幕,进度条,并根据需要播放声音/音乐。这里有一个结构的例子:

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

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

+0

我很期待这样做,因为这将是我通常会用其他语言(IOC等)的方法。我会玩一玩,然后尝试并实施您的建议 - 我期待的是让视图控制器中的声音数量达到最小。 另外,请你能详细解释一下你最后一句话吗? – djskinner 2012-08-13 12:36:26

+0

“记住保持该属性的处理同步” - 意味着如果您正在从多个线程访问资源,则需要确保此线程不被同时读写。您可以使用@ synchronized-blocks或使用原子属性(非非原子)并通过getter/setter方法访问它们。 – 2012-08-13 13:23:04

+0

通过试图避免viewcontroller类中的代码,您正在定义正确的轨道。保持最小值可以为您节省大量头痛,并使您的应用程序更易于维护,扩展和重用。保持! – 2012-08-13 13:23:32